diff --git a/.gitignore b/.gitignore
index 96a556ae1..030625b50 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@ out/
 .idea/
 .vscode/
 .fleet/
+.kotlin/
 
 
 # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
diff --git a/.space.kts b/.space.kts
index ce52a2f5c..45c84ae3d 100644
--- a/.space.kts
+++ b/.space.kts
@@ -34,7 +34,7 @@ job("Publish") {
             api.space().projects.automation.deployments.start(
                 project = api.projectIdentifier(),
                 targetIdentifier = TargetIdentifier.Key(projectName),
-                version = version+revisionSuffix,
+                version = version + revisionSuffix,
                 // automatically update deployment status based on the status of a job
                 syncWithAutomationJob = true
             )
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2f011881f..6bf936c10 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,9 +14,51 @@
 
 ### Security
 
+## 0.4.0-dev-3 - 2024-02-18
+
+### Added
+
+- Reification. Explicit `SafeType` for algebras.
+- Integer division algebras.
+- Float32 geometries.
+- New Attributes-kt module that could be used as stand-alone. It declares. type-safe attributes containers.
+- Explicit `mutableStructureND` builders for mutable structures.
+- `Buffer.asList()` zero-copy transformation.
+- Wasm support.
+- Parallel implementation of `LinearSpace` for Float64
+- Parallel buffer factories
+
+### Changed
+
+- Buffer copy removed from API (added as an extension).
+- Default naming for algebra and buffers now uses IntXX/FloatXX notation instead of Java types.
+- Remove unnecessary inlines in basic algebras.
+- QuaternionField -> QuaternionAlgebra and does not implement `Field` anymore since it is non-commutative
+- kmath-geometry is split into `euclidean2d` and `euclidean3d`
+- Features replaced with Attributes.
+- Transposed refactored.
+- Kmath-memory is moved on top of core.
+
+### Deprecated
+
+- ND4J engine
+
+### Removed
+
+- `asPolynomial` function due to scope pollution
+- Codegend for ejml (450 lines of codegen for 1000 lines of code is too much)
+
+### Fixed
+
+- Median statistics
+- Complex power of negative real numbers
+- Add proper mutability for MutableBufferND rows and columns
+- Generic Float32 and Float64 vectors are used in geometry algebras.
+
 ## 0.3.1 - 2023-04-09
 
 ### Added
+
 - Wasm support for `memory`, `core`, `complex` and `functions` modules.
 - Generic builders for `BufferND` and `MutableBufferND`
 - `NamedMatrix` - matrix with symbol-based indexing
@@ -26,6 +68,8 @@
 - Algebra now has an obligatory `bufferFactory` (#477).
 
 ### Changed
+
+- Removed marker `Vector` type for geometry
 - Geometry uses type-safe angles
 - Tensor operations switched to prefix notation
 - Row-wise and column-wise ND shapes in the core
@@ -33,16 +77,19 @@
 - Major refactor of tensors (only minor API changes)
 - Kotlin 1.8.20
 - `LazyStructure` `deffered` -> `async` to comply with coroutines code style
-- Default `dot` operation in tensor algebra no longer support broadcasting. Instead `matmul` operation is added to `DoubleTensorAlgebra`.
+- Default `dot` operation in tensor algebra no longer support broadcasting. Instead `matmul` operation is added
+  to `DoubleTensorAlgebra`.
 - Multik went MPP
 
 ### Removed
+
 - Trajectory moved to https://github.com/SciProgCentre/maps-kt
 - Polynomials moved to https://github.com/SciProgCentre/kmath-polynomial
 
 ## 0.3.0
 
 ### Added
+
 - `ScaleOperations` interface
 - `Field` extends `ScaleOperations`
 - Basic integration API
@@ -67,6 +114,7 @@
 - Compilation to TeX for MST: #254
 
 ### Changed
+
 - Annotations moved to `space.kscience.kmath`
 - Exponential operations merged with hyperbolic functions
 - Space is replaced by Group. Space is reserved for vector spaces.
@@ -100,9 +148,11 @@
 - `UnivariateFunction` -> `Function1D`, `MultivariateFunction` -> `FunctionND`
 
 ### Deprecated
+
 - Specialized `DoubleBufferAlgebra`
 
 ### Removed
+
 - Nearest in Domain. To be implemented in geometry package.
 - Number multiplication and division in main Algebra chain
 - `contentEquals` from Buffer. It moved to the companion.
@@ -113,12 +163,14 @@
 - Algebra elements are completely removed. Use algebra contexts instead.
 
 ### Fixed
+
 - Ring inherits RingOperations, not GroupOperations
 - Univariate histogram filling
 
 ## 0.2.0
 
 ### Added
+
 - `fun` annotation for SAM interfaces in library
 - Explicit `public` visibility for all public APIs
 - Better trigonometric and hyperbolic functions for `AutoDiffField` (https://github.com/mipt-npm/kmath/pull/140)
@@ -138,6 +190,7 @@
 - Basic Quaternion vector support in `kmath-complex`.
 
 ### Changed
+
 - Package changed from `scientifik` to `space.kscience`
 - Gradle version: 6.6 -> 6.8.2
 - Minor exceptions refactor (throwing `IllegalArgumentException` by argument checks instead of `IllegalStateException`)
@@ -162,6 +215,7 @@
 - Add `out` projection to `Buffer` generic
 
 ### Removed
+
 - `kmath-koma` module because it doesn't support Kotlin 1.4.
 - Support of `legacy` JS backend (we will support only IR)
 - `toGrid` method.
@@ -170,20 +224,24 @@
 - StructureND identity and equals
 
 ### Fixed
+
 - `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140)
 
 ## 0.1.4
 
 ### Added
+
 - Functional Expressions API
 - Mathematical Syntax Tree, its interpreter and API
 - String to MST parser (https://github.com/mipt-npm/kmath/pull/120)
 - MST to JVM bytecode translator (https://github.com/mipt-npm/kmath/pull/94)
 - FloatBuffer (specialized MutableBuffer over FloatArray)
 - FlaggedBuffer to associate primitive numbers buffer with flags (to mark values infinite or missing, etc.)
-- Specialized builder functions for all primitive buffers like `IntBuffer(25) { it + 1 }` (https://github.com/mipt-npm/kmath/pull/125)
+- Specialized builder functions for all primitive buffers
+  like `IntBuffer(25) { it + 1 }` (https://github.com/mipt-npm/kmath/pull/125)
 - Interface `NumericAlgebra` where `number` operation is available to convert numbers to algebraic elements
-- Inverse trigonometric functions support in ExtendedField (`asin`, `acos`, `atan`) (https://github.com/mipt-npm/kmath/pull/114)
+- Inverse trigonometric functions support in
+  ExtendedField (`asin`, `acos`, `atan`) (https://github.com/mipt-npm/kmath/pull/114)
 - New space extensions: `average` and `averageWith`
 - Local coding conventions
 - Geometric Domains API in `kmath-core`
@@ -192,10 +250,12 @@
 - Norm support for `Complex`
 
 ### Changed
+
 - `readAsMemory` now has `throws IOException` in JVM signature.
 - Several functions taking functional types were made `inline`.
 - Several functions taking functional types now have `callsInPlace` contracts.
-- BigInteger and BigDecimal algebra: JBigDecimalField has companion object with default math context; minor optimizations
+- BigInteger and BigDecimal algebra: JBigDecimalField has companion object with default math context; minor
+  optimizations
 - `power(T, Int)` extension function has preconditions and supports `Field<T>`
 - Memory objects have more preconditions (overflow checking)
 - `tg` function is renamed to `tan` (https://github.com/mipt-npm/kmath/pull/114)
@@ -203,6 +263,7 @@
 - Moved probability distributions to commons-rng and to `kmath-prob`
 
 ### Fixed
+
 - Missing copy method in Memory implementation on JS (https://github.com/mipt-npm/kmath/pull/106)
 - D3.dim value in `kmath-dimensions`
 - Multiplication in integer rings in `kmath-core` (https://github.com/mipt-npm/kmath/pull/101)
diff --git a/README.md b/README.md
index 7c1f759c1..1abd7481a 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 [![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382)
 ![Gradle build](https://github.com/SciProgCentre/kmath/workflows/Gradle%20build/badge.svg)
 [![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22)
-[![Space](https://img.shields.io/badge/dynamic/xml?color=orange&label=Space&query=//metadata/versioning/latest&url=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fspace%2Fkscience%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/spc/p/sci/maven/space/kscience/)
+[![Space](https://img.shields.io/badge/dynamic/xml?color=orange&label=Space&query=//metadata/versioning/latest&url=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fspace%2Fkscience%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/)
 
 # KMath
 
@@ -11,18 +11,22 @@ analog to Python's NumPy library. Later we found that kotlin is much more flexib
 architecture designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like
 experience could be achieved with [kmath-for-real](/kmath-for-real) extension module.
 
-[Documentation site (**WIP**)](https://SciProgCentre.github.io/kmath/)
+[Documentation site](https://SciProgCentre.github.io/kmath/)
 
 ## Publications and talks
 
 * [A conceptual article about context-oriented design](https://proandroiddev.com/an-introduction-context-oriented-programming-in-kotlin-2e79d316b0a2)
 * [Another article about context-oriented design](https://proandroiddev.com/diving-deeper-into-context-oriented-programming-in-kotlin-3ecb4ec38814)
 * [ACAT 2019 conference paper](https://aip.scitation.org/doi/abs/10.1063/1.5130103)
+* [A talk at KotlinConf 2019 about using kotlin for science](https://youtu.be/LI_5TZ7tnOE?si=4LknX41gl_YeUbIe)
+* [A talk on architecture at Joker-2021 (in Russian)](https://youtu.be/1bZ2doHiRRM?si=9w953ro9yu98X_KJ)
+* [The same talk in English](https://youtu.be/yP5DIc2fVwQ?si=louZzQ1dcXV6gP10)
+* [A seminar on tensor API](https://youtu.be/0H99wUs0xTM?si=6c__04jrByFQtVpo)
 
 # Goal
 
-* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native)
-  .
+* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS, Native and
+  Wasm).
 * Provide basic multiplatform implementations for those abstractions (without significant performance optimization).
 * Provide bindings and wrappers with those abstractions for popular optimized platform libraries.
 
@@ -53,18 +57,20 @@ module definitions below. The module stability could have the following levels:
 ## Modules
 
 
+### [attributes-kt](attributes-kt)
+> An API and basic implementation for arranging objects in a continuous memory block.
+>
+> **Maturity**: DEVELOPMENT
+
 ### [benchmarks](benchmarks)
-> 
 >
 > **Maturity**: EXPERIMENTAL
 
 ### [examples](examples)
-> 
 >
 > **Maturity**: EXPERIMENTAL
 
 ### [kmath-ast](kmath-ast)
-> 
 >
 > **Maturity**: EXPERIMENTAL
 >
@@ -76,7 +82,7 @@ module definitions below. The module stability could have the following levels:
 
 
 ### [kmath-commons](kmath-commons)
-> 
+> Commons math binding for kmath
 >
 > **Maturity**: EXPERIMENTAL
 
@@ -105,20 +111,19 @@ objects to the expression by providing a context. Expressions can be used for a
 performance calculations to code generation.
 > - [domains](kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains) : Domains
 > - [autodiff](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
+> - [Parallel linear algebra](kmath-core/#) : Parallel implementation for `LinearAlgebra`
 
 
 ### [kmath-coroutines](kmath-coroutines)
-> 
 >
 > **Maturity**: EXPERIMENTAL
 
 ### [kmath-dimensions](kmath-dimensions)
-> 
+> A proof of concept module for adding type-safe dimensions to structures
 >
 > **Maturity**: PROTOTYPE
 
 ### [kmath-ejml](kmath-ejml)
-> 
 >
 > **Maturity**: PROTOTYPE
 >
@@ -142,7 +147,7 @@ One can still use generic algebras though.
 
 
 ### [kmath-functions](kmath-functions)
-> 
+> Functions, integration and interpolation
 >
 > **Maturity**: EXPERIMENTAL
 >
@@ -155,31 +160,28 @@ One can still use generic algebras though.
 
 
 ### [kmath-geometry](kmath-geometry)
-> 
 >
 > **Maturity**: PROTOTYPE
 
 ### [kmath-histograms](kmath-histograms)
-> 
 >
 > **Maturity**: PROTOTYPE
 
 ### [kmath-jafama](kmath-jafama)
-> 
+> Jafama integration module
 >
-> **Maturity**: PROTOTYPE
+> **Maturity**: DEPRECATED
 >
 > **Features:**
 > - [jafama-double](kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/) : Double ExtendedField implementations based on Jafama
 
 
 ### [kmath-jupyter](kmath-jupyter)
-> 
 >
 > **Maturity**: PROTOTYPE
 
 ### [kmath-kotlingrad](kmath-kotlingrad)
-> 
+> Kotlin∇ integration module
 >
 > **Maturity**: EXPERIMENTAL
 >
@@ -194,14 +196,14 @@ One can still use generic algebras though.
 > **Maturity**: DEVELOPMENT
 
 ### [kmath-multik](kmath-multik)
-> 
+> JetBrains Multik connector
 >
 > **Maturity**: PROTOTYPE
 
 ### [kmath-nd4j](kmath-nd4j)
-> 
+> ND4J NDStructure implementation and according NDAlgebra classes
 >
-> **Maturity**: EXPERIMENTAL
+> **Maturity**: DEPRECATED
 >
 > **Features:**
 > - [nd4jarraystructure](kmath-nd4j/#) : NDStructure wrapper for INDArray
@@ -210,27 +212,24 @@ One can still use generic algebras though.
 
 
 ### [kmath-optimization](kmath-optimization)
-> 
 >
 > **Maturity**: EXPERIMENTAL
 
 ### [kmath-stat](kmath-stat)
-> 
 >
 > **Maturity**: EXPERIMENTAL
 
 ### [kmath-symja](kmath-symja)
-> 
+> Symja integration module
 >
 > **Maturity**: PROTOTYPE
 
 ### [kmath-tensorflow](kmath-tensorflow)
-> 
+> Google tensorflow connector
 >
 > **Maturity**: PROTOTYPE
 
 ### [kmath-tensors](kmath-tensors)
-> 
 >
 > **Maturity**: PROTOTYPE
 >
@@ -241,12 +240,11 @@ One can still use generic algebras though.
 
 
 ### [kmath-viktor](kmath-viktor)
-> 
+> Binding for https://github.com/JetBrains-Research/viktor
 >
-> **Maturity**: DEVELOPMENT
+> **Maturity**: DEPRECATED
 
 ### [test-utils](test-utils)
-> 
 >
 > **Maturity**: EXPERIMENTAL
 
@@ -256,22 +254,24 @@ One can still use generic algebras though.
 KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the
 [common source sets](/kmath-core/src/commonMain) and implemented there wherever it is possible. In some cases, features
 are delegated to platform-specific implementations even if they could be provided in the common module for performance
-reasons. Currently, the Kotlin/JVM is the primary platform, however Kotlin/Native and Kotlin/JS contributions and
+reasons. Currently, Kotlin/JVM is the primary platform, however, Kotlin/Native and Kotlin/JS contributions and
 feedback are also welcome.
 
 ## Performance
 
-Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve both
+Calculation of performance is one of the major goals of KMath in the future, but in some cases it is impossible to
+achieve both
 performance and flexibility.
 
-We expect to focus on creating convenient universal API first and then work on increasing performance for specific
+We expect to focus on creating a convenient universal API first and then work on increasing performance for specific
 cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized
-native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be better than SciPy.
+native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be
+better than SciPy.
 
 ## Requirements
 
-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.
+KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend using GraalVM-CE or
+Oracle GraalVM for execution to get better performance.
 
 ### Repositories
 
@@ -291,10 +291,10 @@ dependencies {
 }
 ```
 
-Gradle `6.0+` is required for multiplatform artifacts.
-
 ## Contributing
 
-The project requires a lot of additional work. The most important thing we need is a feedback about what features are
+The project requires a lot of additional work. The most important thing we need is feedback about what features are
 required the most. Feel free to create feature requests. We are also welcome to code contributions, especially in issues
-marked with [waiting for a hero](https://github.com/SciProgCentre/kmath/labels/waiting%20for%20a%20hero) label.
\ No newline at end of file
+marked
+with [good first issue](hhttps://github.com/SciProgCentre/kmath/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
+label.
\ No newline at end of file
diff --git a/attributes-kt/README.md b/attributes-kt/README.md
new file mode 100644
index 000000000..96d273d5b
--- /dev/null
+++ b/attributes-kt/README.md
@@ -0,0 +1,21 @@
+# Module attributes-kt
+
+
+
+## Usage
+
+## Artifact:
+
+The Maven coordinates of this project are `space.kscience:attributes-kt:0.1.0`.
+
+**Gradle Kotlin DSL:**
+```kotlin
+repositories {
+    maven("https://repo.kotlin.link")
+    mavenCentral()
+}
+
+dependencies {
+    implementation("space.kscience:attributes-kt:0.1.0")
+}
+```
diff --git a/attributes-kt/api/attributes-kt.api b/attributes-kt/api/attributes-kt.api
new file mode 100644
index 000000000..c735ad1dc
--- /dev/null
+++ b/attributes-kt/api/attributes-kt.api
@@ -0,0 +1,104 @@
+public abstract interface class space/kscience/attributes/Attribute {
+}
+
+public abstract interface class space/kscience/attributes/AttributeContainer {
+	public abstract fun getAttributes ()Lspace/kscience/attributes/Attributes;
+}
+
+public abstract interface class space/kscience/attributes/AttributeScope {
+}
+
+public abstract interface class space/kscience/attributes/AttributeWithDefault : space/kscience/attributes/Attribute {
+	public abstract fun getDefault ()Ljava/lang/Object;
+}
+
+public abstract interface class space/kscience/attributes/Attributes {
+	public static final field Companion Lspace/kscience/attributes/Attributes$Companion;
+	public abstract fun equals (Ljava/lang/Object;)Z
+	public fun get (Lspace/kscience/attributes/Attribute;)Ljava/lang/Object;
+	public abstract fun getContent ()Ljava/util/Map;
+	public fun getKeys ()Ljava/util/Set;
+	public abstract fun hashCode ()I
+	public abstract fun toString ()Ljava/lang/String;
+}
+
+public final class space/kscience/attributes/Attributes$Companion {
+	public final fun equals (Lspace/kscience/attributes/Attributes;Lspace/kscience/attributes/Attributes;)Z
+	public final fun getEMPTY ()Lspace/kscience/attributes/Attributes;
+}
+
+public final class space/kscience/attributes/AttributesBuilder : space/kscience/attributes/Attributes {
+	public final fun add (Lspace/kscience/attributes/SetAttribute;Ljava/lang/Object;)V
+	public final fun build ()Lspace/kscience/attributes/Attributes;
+	public fun equals (Ljava/lang/Object;)Z
+	public fun getContent ()Ljava/util/Map;
+	public fun hashCode ()I
+	public final fun invoke (Lspace/kscience/attributes/Attribute;Ljava/lang/Object;)V
+	public final fun put (Lspace/kscience/attributes/Attribute;Ljava/lang/Object;)V
+	public final fun putAll (Lspace/kscience/attributes/Attributes;)V
+	public final fun remove (Lspace/kscience/attributes/SetAttribute;Ljava/lang/Object;)V
+	public final fun set (Lspace/kscience/attributes/Attribute;Ljava/lang/Object;)V
+	public fun toString ()Ljava/lang/String;
+}
+
+public final class space/kscience/attributes/AttributesBuilderKt {
+	public static final fun Attributes (Lkotlin/jvm/functions/Function1;)Lspace/kscience/attributes/Attributes;
+}
+
+public final class space/kscience/attributes/AttributesKt {
+	public static final fun Attributes (Lspace/kscience/attributes/Attribute;)Lspace/kscience/attributes/Attributes;
+	public static final fun Attributes (Lspace/kscience/attributes/Attribute;Ljava/lang/Object;)Lspace/kscience/attributes/Attributes;
+	public static final fun getOrDefault (Lspace/kscience/attributes/Attributes;Lspace/kscience/attributes/AttributeWithDefault;)Ljava/lang/Object;
+	public static final fun isEmpty (Lspace/kscience/attributes/Attributes;)Z
+	public static final fun modified (Lspace/kscience/attributes/Attributes;Lkotlin/jvm/functions/Function1;)Lspace/kscience/attributes/Attributes;
+	public static final fun plus (Lspace/kscience/attributes/Attributes;Lspace/kscience/attributes/Attributes;)Lspace/kscience/attributes/Attributes;
+	public static final fun withAttribute (Lspace/kscience/attributes/Attributes;Lspace/kscience/attributes/Attribute;)Lspace/kscience/attributes/Attributes;
+	public static final fun withAttribute (Lspace/kscience/attributes/Attributes;Lspace/kscience/attributes/Attribute;Ljava/lang/Object;)Lspace/kscience/attributes/Attributes;
+	public static final fun withAttributeElement (Lspace/kscience/attributes/Attributes;Lspace/kscience/attributes/SetAttribute;Ljava/lang/Object;)Lspace/kscience/attributes/Attributes;
+	public static final fun withoutAttribute (Lspace/kscience/attributes/Attributes;Lspace/kscience/attributes/Attribute;)Lspace/kscience/attributes/Attributes;
+	public static final fun withoutAttributeElement (Lspace/kscience/attributes/Attributes;Lspace/kscience/attributes/SetAttribute;Ljava/lang/Object;)Lspace/kscience/attributes/Attributes;
+}
+
+public abstract interface class space/kscience/attributes/FlagAttribute : space/kscience/attributes/Attribute {
+}
+
+public abstract class space/kscience/attributes/PolymorphicAttribute : space/kscience/attributes/Attribute {
+	public synthetic fun <init> (Lkotlin/reflect/KType;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+	public fun equals (Ljava/lang/Object;)Z
+	public final fun getType-V0oMfBY ()Lkotlin/reflect/KType;
+	public fun hashCode ()I
+}
+
+public final class space/kscience/attributes/PolymorphicAttributeKt {
+	public static final fun get (Lspace/kscience/attributes/Attributes;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;
+	public static final fun set (Lspace/kscience/attributes/AttributesBuilder;Lkotlin/jvm/functions/Function0;Ljava/lang/Object;)V
+}
+
+public final class space/kscience/attributes/SafeType {
+	public static final synthetic fun box-impl (Lkotlin/reflect/KType;)Lspace/kscience/attributes/SafeType;
+	public static fun constructor-impl (Lkotlin/reflect/KType;)Lkotlin/reflect/KType;
+	public fun equals (Ljava/lang/Object;)Z
+	public static fun equals-impl (Lkotlin/reflect/KType;Ljava/lang/Object;)Z
+	public static final fun equals-impl0 (Lkotlin/reflect/KType;Lkotlin/reflect/KType;)Z
+	public final fun getKType ()Lkotlin/reflect/KType;
+	public fun hashCode ()I
+	public static fun hashCode-impl (Lkotlin/reflect/KType;)I
+	public fun toString ()Ljava/lang/String;
+	public static fun toString-impl (Lkotlin/reflect/KType;)Ljava/lang/String;
+	public final synthetic fun unbox-impl ()Lkotlin/reflect/KType;
+}
+
+public final class space/kscience/attributes/SafeTypeKt {
+	public static final fun getKClass-X0YbwmU (Lkotlin/reflect/KType;)Lkotlin/reflect/KClass;
+}
+
+public abstract interface class space/kscience/attributes/SetAttribute : space/kscience/attributes/Attribute {
+}
+
+public abstract interface annotation class space/kscience/attributes/UnstableAttributesAPI : java/lang/annotation/Annotation {
+}
+
+public abstract interface class space/kscience/attributes/WithType {
+	public abstract fun getType-V0oMfBY ()Lkotlin/reflect/KType;
+}
+
diff --git a/attributes-kt/build.gradle.kts b/attributes-kt/build.gradle.kts
new file mode 100644
index 000000000..555567aac
--- /dev/null
+++ b/attributes-kt/build.gradle.kts
@@ -0,0 +1,20 @@
+plugins {
+    id("space.kscience.gradle.mpp")
+    `maven-publish`
+}
+
+version = rootProject.extra.get("attributesVersion").toString()
+
+kscience {
+    jvm()
+    js()
+    native()
+    wasm()
+}
+
+readme {
+    maturity = space.kscience.gradle.Maturity.DEVELOPMENT
+    description = """
+        An API and basic implementation for arranging objects in a continuous memory block.
+    """.trimIndent()
+}
diff --git a/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/Attribute.kt b/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/Attribute.kt
new file mode 100644
index 000000000..9142cafdb
--- /dev/null
+++ b/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/Attribute.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2018-2023 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.attributes
+
+/**
+ * A marker interface for an attribute. Attributes are used as keys to access contents of type [T] in the container.
+ */
+public interface Attribute<T>
+
+/**
+ * An attribute that could be either present or absent
+ */
+public interface FlagAttribute : Attribute<Unit>
+
+/**
+ * An attribute with a default value
+ */
+public interface AttributeWithDefault<T> : Attribute<T> {
+    public val default: T
+}
+
+/**
+ * Attribute containing a set of values
+ */
+public interface SetAttribute<V> : Attribute<Set<V>>
+
diff --git a/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/AttributeContainer.kt b/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/AttributeContainer.kt
new file mode 100644
index 000000000..734887bdb
--- /dev/null
+++ b/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/AttributeContainer.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2018-2023 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.attributes
+
+/**
+ * A container for [Attributes]
+ */
+public interface AttributeContainer {
+    public val attributes: Attributes
+}
+
+/**
+ * A scope, where attribute keys could be resolved.
+ * [O] is used only to resolve types in compile-time.
+ */
+public interface AttributeScope<O>
+
diff --git a/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/Attributes.kt b/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/Attributes.kt
new file mode 100644
index 000000000..ab6185520
--- /dev/null
+++ b/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/Attributes.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2018-2023 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.attributes
+
+/**
+ * A set of attributes. The implementation must guarantee that [content] keys correspond to their value types.
+ */
+public interface Attributes {
+    /**
+     * Raw content for this [Attributes]
+     */
+    public val content: Map<out Attribute<*>, Any?>
+
+    /**
+     * Attribute keys contained in this [Attributes]
+     */
+    public val keys: Set<Attribute<*>> get() = content.keys
+
+    /**
+     * Provide an attribute value. Return null if attribute is not present or if its value is null.
+     */
+    @Suppress("UNCHECKED_CAST")
+    public operator fun <T> get(attribute: Attribute<T>): T? = content[attribute] as? T
+
+    override fun toString(): String
+    override fun equals(other: Any?): Boolean
+    override fun hashCode(): Int
+
+    public companion object {
+        public val EMPTY: Attributes = object : Attributes {
+            override val content: Map<out Attribute<*>, Any?> get() = emptyMap()
+
+            override fun toString(): String = "Attributes.EMPTY"
+
+            override fun equals(other: Any?): Boolean = (other as? Attributes)?.isEmpty() ?: false
+
+            override fun hashCode(): Int = Unit.hashCode()
+        }
+
+        public fun equals(a1: Attributes, a2: Attributes): Boolean =
+            a1.keys == a2.keys && a1.keys.all { a1[it] == a2[it] }
+    }
+}
+
+internal class MapAttributes(override val content: Map<out Attribute<*>, Any?>) : Attributes {
+    override fun toString(): String = "Attributes(value=${content.entries})"
+    override fun equals(other: Any?): Boolean = other is Attributes && Attributes.equals(this, other)
+    override fun hashCode(): Int = content.hashCode()
+}
+
+public fun Attributes.isEmpty(): Boolean = keys.isEmpty()
+
+/**
+ * Get attribute value or default
+ */
+public fun <T> Attributes.getOrDefault(attribute: AttributeWithDefault<T>): T = get(attribute) ?: attribute.default
+
+/**
+ * Check if there is an attribute that matches given key by type and adheres to [predicate].
+ */
+@Suppress("UNCHECKED_CAST")
+public inline fun <T, reified A : Attribute<T>> Attributes.hasAny(predicate: (value: T) -> Boolean): Boolean =
+    content.any { (mapKey, mapValue) -> mapKey is A && predicate(mapValue as T) }
+
+/**
+ * Check if there is an attribute of given type (subtypes included)
+ */
+public inline fun <reified A : Attribute<*>> Attributes.hasAny(): Boolean =
+    content.any { (mapKey, _) -> mapKey is A }
+
+/**
+ * Check if [Attributes] contains a flag. Multiple keys that are instances of a flag could be present
+ */
+public inline fun <reified A : FlagAttribute> Attributes.hasFlag(): Boolean =
+    content.keys.any { it is A }
+
+/**
+ * Create [Attributes] with an added or replaced attribute key.
+ */
+public fun <T, A : Attribute<T>> Attributes.withAttribute(
+    attribute: A,
+    attrValue: T,
+): Attributes = MapAttributes(content + (attribute to attrValue))
+
+public fun <A : Attribute<Unit>> Attributes.withAttribute(attribute: A): Attributes =
+    withAttribute(attribute, Unit)
+
+/**
+ * Create a new [Attributes] by modifying the current one
+ */
+public fun <O> Attributes.modified(block: AttributesBuilder<O>.() -> Unit): Attributes = Attributes<O> {
+    putAll(this@modified)
+    block()
+}
+
+/**
+ * Create new [Attributes] by removing [attribute] key
+ */
+public fun Attributes.withoutAttribute(attribute: Attribute<*>): Attributes = MapAttributes(content.minus(attribute))
+
+/**
+ * Add an element to a [SetAttribute]
+ */
+public fun <T, A : SetAttribute<T>> Attributes.withAttributeElement(
+    attribute: A,
+    attrValue: T,
+): Attributes {
+    val currentSet: Set<T> = get(attribute) ?: emptySet()
+    return MapAttributes(
+        content + (attribute to (currentSet + attrValue))
+    )
+}
+
+/**
+ * Remove an element from [SetAttribute]
+ */
+public fun <T, A : SetAttribute<T>> Attributes.withoutAttributeElement(
+    attribute: A,
+    attrValue: T,
+): Attributes {
+    val currentSet: Set<T> = get(attribute) ?: emptySet()
+    return MapAttributes(content + (attribute to (currentSet - attrValue)))
+}
+
+/**
+ * Create [Attributes] with a single key
+ */
+public fun <T, A : Attribute<T>> Attributes(
+    attribute: A,
+    attrValue: T,
+): Attributes = MapAttributes(mapOf(attribute to attrValue))
+
+/**
+ * Create Attributes with a single [Unit] valued attribute
+ */
+public fun <A : Attribute<Unit>> Attributes(
+    attribute: A,
+): Attributes = MapAttributes(mapOf(attribute to Unit))
+
+public operator fun Attributes.plus(other: Attributes): Attributes = MapAttributes(content + other.content)
\ No newline at end of file
diff --git a/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/AttributesBuilder.kt b/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/AttributesBuilder.kt
new file mode 100644
index 000000000..ecf3da6f2
--- /dev/null
+++ b/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/AttributesBuilder.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2018-2023 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.attributes
+
+/**
+ * A builder for [Attributes].
+ * The builder is not thread safe
+ *
+ * @param O type marker of an owner object, for which these attributes are made
+ */
+public class AttributesBuilder<out O> internal constructor() : Attributes {
+
+    private val map = mutableMapOf<Attribute<*>, Any?>()
+
+    override fun toString(): String = "Attributes(value=${map.entries})"
+    override fun equals(other: Any?): Boolean = other is Attributes && Attributes.equals(this, other)
+    override fun hashCode(): Int = map.hashCode()
+
+    override val content: Map<out Attribute<*>, Any?> get() = map
+
+    public operator fun <T> set(attribute: Attribute<T>, value: T?) {
+        if (value == null) {
+            map.remove(attribute)
+        } else {
+            map[attribute] = value
+        }
+    }
+
+    public operator fun <V> Attribute<V>.invoke(value: V?) {
+        set(this, value)
+    }
+
+    public infix fun <V> Attribute<V>.put(value: V?) {
+        set(this, value)
+    }
+
+    /**
+     * Put all attributes for given [attributes]
+     */
+    public fun putAll(attributes: Attributes) {
+        map.putAll(attributes.content)
+    }
+
+    public infix fun <V> SetAttribute<V>.add(attrValue: V) {
+        val currentSet: Set<V> = get(this) ?: emptySet()
+        map[this] = currentSet + attrValue
+    }
+
+    /**
+     * Remove an element from [SetAttribute]
+     */
+    public infix fun <V> SetAttribute<V>.remove(attrValue: V) {
+        val currentSet: Set<V> = get(this) ?: emptySet()
+        map[this] = currentSet - attrValue
+    }
+
+    public fun build(): Attributes = MapAttributes(map)
+}
+
+/**
+ * Create [Attributes] with a given [builder]
+ * @param O the type for which attributes are built. The type is used only during compilation phase for static extension dispatch
+ */
+public fun <O> Attributes(builder: AttributesBuilder<O>.() -> Unit): Attributes =
+    AttributesBuilder<O>().apply(builder).build()
\ No newline at end of file
diff --git a/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/PolymorphicAttribute.kt b/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/PolymorphicAttribute.kt
new file mode 100644
index 000000000..e81d88e46
--- /dev/null
+++ b/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/PolymorphicAttribute.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2018-2023 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.attributes
+
+/**
+ * An attribute that has a type parameter for value
+ * @param type parameter-type
+ */
+public abstract class PolymorphicAttribute<T>(public val type: SafeType<T>) : Attribute<T> {
+    override fun equals(other: Any?): Boolean = other != null &&
+            (this::class == other::class) &&
+            (other as? PolymorphicAttribute<*>)?.type == this.type
+
+    override fun hashCode(): Int = this::class.hashCode() + type.hashCode()
+}
+
+
+/**
+ * Get a polymorphic attribute using attribute factory
+ */
+@UnstableAttributesAPI
+public operator fun <T> Attributes.get(attributeKeyBuilder: () -> PolymorphicAttribute<T>): T? =
+    get(attributeKeyBuilder())
+
+/**
+ * Set a polymorphic attribute using its factory
+ */
+@UnstableAttributesAPI
+public operator fun <O, T> AttributesBuilder<O>.set(attributeKeyBuilder: () -> PolymorphicAttribute<T>, value: T) {
+    set(attributeKeyBuilder(), value)
+}
diff --git a/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/SafeType.kt b/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/SafeType.kt
new file mode 100644
index 000000000..b76589164
--- /dev/null
+++ b/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/SafeType.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018-2023 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.attributes
+
+import kotlin.jvm.JvmInline
+import kotlin.reflect.KClass
+import kotlin.reflect.KType
+import kotlin.reflect.typeOf
+
+/**
+ * Safe variant ok Kotlin [KType] that ensures that the type parameter is of the same type as [kType]
+ *
+ * @param kType raw [KType]
+ */
+@JvmInline
+public value class SafeType<out T> @PublishedApi internal constructor(public val kType: KType)
+
+public inline fun <reified T> safeTypeOf(): SafeType<T> = SafeType(typeOf<T>())
+
+/**
+ * Derive Kotlin [KClass] from this type and fail if the type is not a class (should not happen)
+ */
+@Suppress("UNCHECKED_CAST")
+@UnstableAttributesAPI
+public val <T> SafeType<T>.kClass: KClass<T & Any> get() = kType.classifier as KClass<T & Any>
+
+/**
+ * An interface containing [type] for dynamic type checking.
+ */
+public interface WithType<out T> {
+    public val type: SafeType<T>
+}
\ No newline at end of file
diff --git a/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/annotations.kt b/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/annotations.kt
new file mode 100644
index 000000000..80d93daaf
--- /dev/null
+++ b/attributes-kt/src/commonMain/kotlin/space/kscience/attributes/annotations.kt
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2018-2023 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.attributes
+
+/**
+ * Marks declarations that are still experimental in the Attributes-kt APIs, which means that the design of the corresponding
+ * declarations has open issues that may (or may not) lead to their changes in the future. Roughly speaking, there is
+ * a chance of those declarations will be deprecated in the future or the semantics of their behavior may change
+ * in some way that may break some code.
+ */
+@MustBeDocumented
+@Retention(value = AnnotationRetention.BINARY)
+@RequiresOptIn("This API is unstable and could change in future", RequiresOptIn.Level.WARNING)
+public annotation class UnstableAttributesAPI
\ No newline at end of file
diff --git a/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt
index cb07e489a..29d4cde79 100644
--- a/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt
+++ b/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -11,7 +11,7 @@ import kotlinx.benchmark.Scope
 import kotlinx.benchmark.State
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.expressions.*
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.bindSymbol
 import space.kscience.kmath.operations.invoke
 import kotlin.math.sin
@@ -84,7 +84,7 @@ class ExpressionsInterpretersBenchmark {
         private val x by symbol
         private const val times = 1_000_000
 
-        private val functional = DoubleField.expression {
+        private val functional = Float64Field.expression {
             val x = bindSymbol(Symbol.x)
             x * number(2.0) + 2.0 / x - 16.0 / sin(x)
         }
@@ -93,13 +93,14 @@ class ExpressionsInterpretersBenchmark {
             x * 2.0 + number(2.0) / x - number(16.0) / sin(x)
         }
 
-        private val mst = node.toExpression(DoubleField)
+        private val mst = node.toExpression(Float64Field)
+
         @OptIn(UnstableKMathAPI::class)
-        private val wasm = node.wasmCompileToExpression(DoubleField)
-        private val estree = node.estreeCompileToExpression(DoubleField)
+        private val wasm = node.wasmCompileToExpression(Float64Field)
+        private val estree = node.estreeCompileToExpression(Float64Field)
 
         private val raw = Expression<Double> { args ->
-            val x = args[x]!!
+            val x = args.getValue(x)
             x * 2.0 + 2.0 / x - 16.0 / sin(x)
         }
     }
diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt
index abfc8cbf2..f04f0a46d 100644
--- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt
index d07b7b4df..a4c2855f1 100644
--- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -67,7 +67,7 @@ internal class BigIntBenchmark {
 
     @Benchmark
     fun kmMultiplyLarge(blackhole: Blackhole) = BigIntField {
-        blackhole.consume(kmLargeNumber*kmLargeNumber)
+        blackhole.consume(kmLargeNumber * kmLargeNumber)
     }
 
     @Benchmark
@@ -77,7 +77,7 @@ internal class BigIntBenchmark {
 
     @Benchmark
     fun jvmMultiplyLarge(blackhole: Blackhole) = JBigIntegerField {
-        blackhole.consume(jvmLargeNumber*jvmLargeNumber)
+        blackhole.consume(jvmLargeNumber * jvmLargeNumber)
     }
 
     @Benchmark
diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt
index c2616303b..a37d12ffb 100644
--- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -14,7 +14,7 @@ import space.kscience.kmath.complex.ComplexField
 import space.kscience.kmath.complex.complex
 import space.kscience.kmath.operations.invoke
 import space.kscience.kmath.structures.Buffer
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import space.kscience.kmath.structures.getDouble
 import space.kscience.kmath.structures.permute
 
@@ -33,7 +33,7 @@ internal class BufferBenchmark {
 
     @Benchmark
     fun doubleBufferReadWrite(blackhole: Blackhole) {
-        val buffer = DoubleBuffer(size) { it.toDouble() }
+        val buffer = Float64Buffer(size) { it.toDouble() }
         var res = 0.0
         (0 until size).forEach {
             res += buffer[it]
@@ -43,7 +43,7 @@ internal class BufferBenchmark {
 
     @Benchmark
     fun bufferViewReadWrite(blackhole: Blackhole) {
-        val buffer = DoubleBuffer(size) { it.toDouble() }.permute(reversedIndices)
+        val buffer = Float64Buffer(size) { it.toDouble() }.permute(reversedIndices)
         var res = 0.0
         (0 until size).forEach {
             res += buffer[it]
@@ -53,7 +53,7 @@ internal class BufferBenchmark {
 
     @Benchmark
     fun bufferViewReadWriteSpecialized(blackhole: Blackhole) {
-        val buffer = DoubleBuffer(size) { it.toDouble() }.permute(reversedIndices)
+        val buffer = Float64Buffer(size) { it.toDouble() }.permute(reversedIndices)
         var res = 0.0
         (0 until size).forEach {
             res += buffer.getDouble(it)
@@ -75,6 +75,6 @@ internal class BufferBenchmark {
 
     private companion object {
         private const val size = 100
-        private val reversedIndices = IntArray(size){it}.apply { reverse() }
+        private val reversedIndices = IntArray(size) { it }.apply { reverse() }
     }
 }
diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt
index 7cbe83113..a157a67b2 100644
--- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -11,12 +11,11 @@ import kotlinx.benchmark.Scope
 import kotlinx.benchmark.State
 import space.kscience.kmath.commons.linear.CMLinearSpace
 import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM
+import space.kscience.kmath.linear.Float64ParallelLinearSpace
 import space.kscience.kmath.linear.invoke
 import space.kscience.kmath.linear.linearSpace
-import space.kscience.kmath.operations.DoubleField
-import space.kscience.kmath.operations.invoke
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.tensorflow.produceWithTF
-import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
 import space.kscience.kmath.tensors.core.tensorAlgebra
 import kotlin.random.Random
 
@@ -27,10 +26,10 @@ internal class DotBenchmark {
         const val dim = 1000
 
         //creating invertible matrix
-        val matrix1 = DoubleField.linearSpace.buildMatrix(dim, dim) { _, _ ->
+        val matrix1 = Float64Field.linearSpace.buildMatrix(dim, dim) { _, _ ->
             random.nextDouble()
         }
-        val matrix2 = DoubleField.linearSpace.buildMatrix(dim, dim) { _, _ ->
+        val matrix2 = Float64Field.linearSpace.buildMatrix(dim, dim) { _, _ ->
             random.nextDouble()
         }
 
@@ -45,7 +44,7 @@ internal class DotBenchmark {
     @Benchmark
     fun tfDot(blackhole: Blackhole) {
         blackhole.consume(
-            DoubleField.produceWithTF {
+            Float64Field.produceWithTF {
                 matrix1 dot matrix1
             }
         )
@@ -71,28 +70,24 @@ internal class DotBenchmark {
         blackhole.consume(matrix1 dot matrix2)
     }
 
-    @Benchmark
-    fun tensorDot(blackhole: Blackhole) = with(DoubleField.tensorAlgebra) {
-        blackhole.consume(matrix1 dot matrix2)
-    }
-
     @Benchmark
     fun multikDot(blackhole: Blackhole) = with(multikAlgebra) {
         blackhole.consume(matrix1 dot matrix2)
     }
 
     @Benchmark
-    fun bufferedDot(blackhole: Blackhole) = with(DoubleField.linearSpace) {
+    fun tensorDot(blackhole: Blackhole) = with(Float64Field.tensorAlgebra) {
         blackhole.consume(matrix1 dot matrix2)
     }
 
     @Benchmark
-    fun doubleDot(blackhole: Blackhole) = with(DoubleField.linearSpace) {
+    fun bufferedDot(blackhole: Blackhole) = with(Float64Field.linearSpace) {
         blackhole.consume(matrix1 dot matrix2)
     }
 
     @Benchmark
-    fun doubleTensorDot(blackhole: Blackhole) = DoubleTensorAlgebra.invoke {
+    fun parallelDot(blackhole: Blackhole) = with(Float64ParallelLinearSpace) {
         blackhole.consume(matrix1 dot matrix2)
     }
+
 }
diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt
index 4df5f372f..45b3916dc 100644
--- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -12,7 +12,7 @@ import kotlinx.benchmark.State
 import space.kscience.kmath.asm.compileToExpression
 import space.kscience.kmath.expressions.*
 import space.kscience.kmath.operations.Algebra
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.bindSymbol
 import space.kscience.kmath.operations.invoke
 import kotlin.math.sin
@@ -100,7 +100,7 @@ internal class ExpressionsInterpretersBenchmark {
         private val x by symbol
         private const val times = 1_000_000
 
-        private val functional = DoubleField.expression {
+        private val functional = Float64Field.expression {
             val x = bindSymbol(Symbol.x)
             x * number(2.0) + 2.0 / x - 16.0 / sin(x)
         }
@@ -109,12 +109,12 @@ internal class ExpressionsInterpretersBenchmark {
             x * 2.0 + number(2.0) / x - number(16.0) / sin(x)
         }
 
-        private val mst = node.toExpression(DoubleField)
+        private val mst = node.toExpression(Float64Field)
 
-        private val asmPrimitive = node.compileToExpression(DoubleField)
+        private val asmPrimitive = node.compileToExpression(Float64Field)
         private val xIdx = asmPrimitive.indexer.indexOf(x)
 
-        private val asmGeneric = node.compileToExpression(DoubleField as Algebra<Double>)
+        private val asmGeneric = node.compileToExpression(Float64Field as Algebra<Double>)
 
         private val raw = Expression<Double> { args ->
             val x = args[x]!!
diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/IntegrationBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/IntegrationBenchmark.kt
index 6cc649fe9..00f2d908d 100644
--- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/IntegrationBenchmark.kt
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/IntegrationBenchmark.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2023 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -24,7 +24,7 @@ internal class IntegrationBenchmark {
     fun doubleIntegration(blackhole: Blackhole) {
         val res = Double.algebra.gaussIntegrator.integrate(0.0..1.0, intervals = 1000) { x: Double ->
             //sin(1 / x)
-            1/x
+            1 / x
         }.value
         blackhole.consume(res)
     }
@@ -33,7 +33,7 @@ internal class IntegrationBenchmark {
     fun complexIntegration(blackhole: Blackhole) = with(Complex.algebra) {
         val res = gaussIntegrator.integrate(0.0..1.0, intervals = 1000) { x: Double ->
 //            sin(1 / x) + i * cos(1 / x)
-            1/x - i/x
+            1 / x - i / x
         }.value
         blackhole.consume(res)
     }
diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt
index 041f7e92a..b0e029870 100644
--- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -11,10 +11,8 @@ import org.openjdk.jmh.annotations.Scope
 import org.openjdk.jmh.annotations.State
 import space.kscience.kmath.jafama.JafamaDoubleField
 import space.kscience.kmath.jafama.StrictJafamaDoubleField
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.invoke
-import kotlin.contracts.InvocationKind
-import kotlin.contracts.contract
 import kotlin.random.Random
 
 @State(Scope.Benchmark)
@@ -26,7 +24,7 @@ internal class JafamaBenchmark {
 
     @Benchmark
     fun core(blackhole: Blackhole) = invokeBenchmarks(blackhole) { x ->
-        DoubleField { x * power(x, 4) * exp(x) / cos(x) + sin(x) }
+        Float64Field { x * power(x, 4) * exp(x) / cos(x) + sin(x) }
     }
 
     @Benchmark
@@ -36,7 +34,6 @@ internal class JafamaBenchmark {
 }
 
 private inline fun invokeBenchmarks(blackhole: Blackhole, expr: (Double) -> Double) {
-    contract { callsInPlace(expr, InvocationKind.AT_LEAST_ONCE) }
     val rng = Random(0)
     repeat(1000000) { blackhole.consume(expr(rng.nextDouble())) }
 }
diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt
index f7aac8199..1a9e09013 100644
--- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -15,6 +15,7 @@ import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM
 import space.kscience.kmath.linear.invoke
 import space.kscience.kmath.linear.linearSpace
 import space.kscience.kmath.linear.lupSolver
+import space.kscience.kmath.linear.parallel
 import space.kscience.kmath.operations.algebra
 import kotlin.random.Random
 
@@ -38,16 +39,19 @@ internal class MatrixInverseBenchmark {
     }
 
     @Benchmark
-    fun cmLUPInversion(blackhole: Blackhole) {
-        CMLinearSpace {
-            blackhole.consume(lupSolver().inverse(matrix))
-        }
+    fun kmathParallelLupInversion(blackhole: Blackhole) {
+        blackhole.consume(Double.algebra.linearSpace.parallel.lupSolver().inverse(matrix))
     }
 
     @Benchmark
-    fun ejmlInverse(blackhole: Blackhole) {
-        EjmlLinearSpaceDDRM {
-            blackhole.consume(matrix.toEjml().inverse())
-        }
+    fun cmLUPInversion(blackhole: Blackhole) = CMLinearSpace {
+        blackhole.consume(lupSolver().inverse(matrix))
     }
+
+
+    @Benchmark
+    fun ejmlInverse(blackhole: Blackhole) = EjmlLinearSpaceDDRM {
+        blackhole.consume(matrix.toEjml().inverted())
+    }
+
 }
diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt
index fb8d845e8..77ca03099 100644
--- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -16,7 +16,7 @@ import org.jetbrains.kotlinx.multik.ndarray.data.DataType
 import space.kscience.kmath.UnsafeKMathAPI
 import space.kscience.kmath.nd.*
 import space.kscience.kmath.nd4j.nd4j
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.tensors.core.DoubleTensor
 import space.kscience.kmath.tensors.core.one
 import space.kscience.kmath.tensors.core.tensorAlgebra
@@ -25,6 +25,16 @@ import space.kscience.kmath.viktor.viktorAlgebra
 @State(Scope.Benchmark)
 internal class NDFieldBenchmark {
 
+    private companion object {
+        private const val dim = 1000
+        private const val n = 100
+        private val shape = ShapeND(dim, dim)
+        private val specializedField = Float64Field.ndAlgebra
+        private val genericField = BufferedFieldOpsND(Float64Field)
+        private val nd4jField = Float64Field.nd4j
+        private val viktorField = Float64Field.viktorAlgebra
+    }
+
     @Benchmark
     fun specializedFieldAdd(blackhole: Blackhole) = with(specializedField) {
         var res: StructureND<Double> = one(shape)
@@ -82,13 +92,5 @@ internal class NDFieldBenchmark {
 //        blackhole.consume(res)
 //    }
 
-    private companion object {
-        private const val dim = 1000
-        private const val n = 100
-        private val shape = ShapeND(dim, dim)
-        private val specializedField = DoubleField.ndAlgebra
-        private val genericField = BufferedFieldOpsND(DoubleField)
-        private val nd4jField = DoubleField.nd4j
-        private val viktorField = DoubleField.viktorAlgebra
-    }
+
 }
diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/TensorAlgebraBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/TensorAlgebraBenchmark.kt
index c4382374a..64efaf640 100644
--- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/TensorAlgebraBenchmark.kt
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/TensorAlgebraBenchmark.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -12,7 +12,7 @@ import kotlinx.benchmark.State
 import space.kscience.kmath.linear.linearSpace
 import space.kscience.kmath.linear.matrix
 import space.kscience.kmath.linear.symmetric
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.tensors.core.symEigJacobi
 import space.kscience.kmath.tensors.core.symEigSvd
 import space.kscience.kmath.tensors.core.tensorAlgebra
@@ -24,7 +24,7 @@ internal class TensorAlgebraBenchmark {
         private val random = Random(12224)
         private const val dim = 30
 
-        private val matrix = DoubleField.linearSpace.matrix(dim, dim).symmetric { _, _ -> random.nextDouble() }
+        private val matrix = Float64Field.linearSpace.matrix(dim, dim).symmetric { _, _ -> random.nextDouble() }
     }
 
     @Benchmark
diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt
index 90f3cb765..bd5c2006a 100644
--- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -14,7 +14,7 @@ import space.kscience.kmath.nd.ShapeND
 import space.kscience.kmath.nd.StructureND
 import space.kscience.kmath.nd.ndAlgebra
 import space.kscience.kmath.nd.one
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.viktor.ViktorFieldND
 
 @State(Scope.Benchmark)
@@ -52,7 +52,7 @@ internal class ViktorBenchmark {
         private val shape = ShapeND(dim, dim)
 
         // automatically build context most suited for given type.
-        private val doubleField = DoubleField.ndAlgebra
+        private val doubleField = Float64Field.ndAlgebra
         private val viktorField = ViktorFieldND(dim, dim)
     }
 }
diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt
index 4ec4605ed..65d159e54 100644
--- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -13,7 +13,7 @@ import org.jetbrains.bio.viktor.F64Array
 import space.kscience.kmath.nd.ShapeND
 import space.kscience.kmath.nd.ndAlgebra
 import space.kscience.kmath.nd.one
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.viktor.ViktorFieldND
 
 @State(Scope.Benchmark)
@@ -52,7 +52,7 @@ internal class ViktorLogBenchmark {
         private val shape = ShapeND(dim, dim)
 
         // automatically build context most suited for given type.
-        private val doubleField = DoubleField.ndAlgebra
+        private val doubleField = Float64Field.ndAlgebra
         private val viktorField = ViktorFieldND(dim, dim)
     }
 }
diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/globals.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/globals.kt
index f6d278d83..ff5157f81 100644
--- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/globals.kt
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/globals.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/build.gradle.kts b/build.gradle.kts
index fb2f7d8c7..d90529e08 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,12 +1,13 @@
-import space.kscience.gradle.isInDevelopment
 import space.kscience.gradle.useApache2Licence
 import space.kscience.gradle.useSPCTeam
 
 plugins {
     id("space.kscience.gradle.project")
-    id("org.jetbrains.kotlinx.kover") version "0.6.0"
+    id("org.jetbrains.kotlinx.kover") version "0.7.6"
 }
 
+val attributesVersion by extra("0.2.0")
+
 allprojects {
     repositories {
         maven("https://repo.kotlin.link")
@@ -15,7 +16,7 @@ allprojects {
     }
 
     group = "space.kscience"
-    version = "0.3.1"
+    version = "0.4.0"
 }
 
 subprojects {
@@ -35,7 +36,7 @@ subprojects {
                     localDirectory.set(kotlinDir)
 
                     remoteUrl.set(
-                        java.net.URL("https://github.com/SciProgCentre/kmath/tree/master/${this@subprojects.name}/$kotlinDirPath")
+                        uri("https://github.com/SciProgCentre/kmath/tree/master/${this@subprojects.name}/$kotlinDirPath").toURL()
                     )
                 }
 
@@ -64,17 +65,10 @@ ksciencePublish {
         useApache2Licence()
         useSPCTeam()
     }
-    github("kmath", "SciProgCentre")
-    space(
-        if (isInDevelopment) {
-            "https://maven.pkg.jetbrains.space/spc/p/sci/dev"
-        } else {
-            "https://maven.pkg.jetbrains.space/spc/p/sci/maven"
-        }
-    )
-    sonatype()
+    repository("spc", "https://maven.sciprog.center/kscience")
+    sonatype("https://oss.sonatype.org")
 }
 
 apiValidation.nonPublicMarkers.add("space.kscience.kmath.UnstableKMathAPI")
 
-val multikVersion by extra("0.2.0")
+val multikVersion by extra("0.2.3")
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
index 734f60091..ba4c391d8 100644
--- a/buildSrc/build.gradle.kts
+++ b/buildSrc/build.gradle.kts
@@ -17,15 +17,15 @@ val benchmarksVersion = spclibs.versions.kotlinx.benchmark.get()
 dependencies {
     api("space.kscience:gradle-tools:$toolsVersion")
     //plugins form benchmarks
-    api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:0.4.7")
+    api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:$benchmarksVersion")
     //api("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion")
     //to be used inside build-script only
     //implementation(spclibs.kotlinx.serialization.json)
     implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.+")
 }
 
-kotlin{
-    jvmToolchain{
+kotlin {
+    jvmToolchain {
         languageVersion.set(JavaLanguageVersion.of(11))
     }
     sourceSets.all {
diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts
index e6b69b0b3..09633711e 100644
--- a/buildSrc/settings.gradle.kts
+++ b/buildSrc/settings.gradle.kts
@@ -2,10 +2,13 @@
  * Copyright 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.
  */
-rootProject.name = "kmath"
 
 enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
 
+plugins {
+    id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
+}
+
 dependencyResolutionManagement {
     val projectProperties = java.util.Properties()
     file("../gradle.properties").inputStream().use {
@@ -19,6 +22,7 @@ dependencyResolutionManagement {
 
     val toolsVersion: String = projectProperties["toolsVersion"].toString()
 
+    @Suppress("UnstableApiUsage")
     repositories {
         mavenLocal()
         maven("https://repo.kotlin.link")
diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt
index 3a4fcdc79..98778e009 100644
--- a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt
+++ b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt
index a3a475885..ae2083c5f 100644
--- a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt
+++ b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -54,16 +54,17 @@ fun Project.addBenchmarkProperties() {
         p.extensions.findByType(KScienceReadmeExtension::class.java)?.run {
             benchmarksProject.extensions.findByType(BenchmarksExtension::class.java)?.configurations?.forEach { cfg ->
                 property("benchmark${cfg.name.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }}") {
-                    val launches = benchmarksProject.buildDir.resolve("reports/benchmarks/${cfg.name}")
+                    val launches = benchmarksProject.layout.buildDirectory.dir("reports/benchmarks/${cfg.name}").get()
 
-                    val resDirectory = launches.listFiles()?.maxByOrNull {
+                    val resDirectory = launches.files().maxByOrNull {
                         LocalDateTime.parse(it.name, ISO_DATE_TIME).atZone(ZoneId.systemDefault()).toInstant()
                     }
 
                     if (resDirectory == null || !(resDirectory.resolve("jvm.json")).exists()) {
                         "> **Can't find appropriate benchmark data. Try generating readme files after running benchmarks**."
                     } else {
-                        val reports: List<JmhReport> = jsonMapper.readValue<List<JmhReport>>(resDirectory.resolve("jvm.json"))
+                        val reports: List<JmhReport> =
+                            jsonMapper.readValue<List<JmhReport>>(resDirectory.resolve("jvm.json"))
 
                         buildString {
                             appendLine("<details>")
@@ -76,16 +77,20 @@ fun Project.addBenchmarkProperties() {
                             appendLine("* Run on ${first.vmName} (build ${first.vmVersion}) with Java process:")
                             appendLine()
                             appendLine("```")
-                            appendLine("${first.jvm} ${
-                                first.jvmArgs.joinToString(" ")
-                            }")
+                            appendLine(
+                                "${first.jvm} ${
+                                    first.jvmArgs.joinToString(" ")
+                                }"
+                            )
                             appendLine("```")
 
-                            appendLine("* JMH ${first.jmhVersion} was used in `${first.mode}` mode with ${first.warmupIterations} warmup ${
-                                noun(first.warmupIterations, "iteration", "iterations")
-                            } by ${first.warmupTime} and ${first.measurementIterations} measurement ${
-                                noun(first.measurementIterations, "iteration", "iterations")
-                            } by ${first.measurementTime}.")
+                            appendLine(
+                                "* JMH ${first.jmhVersion} was used in `${first.mode}` mode with ${first.warmupIterations} warmup ${
+                                    noun(first.warmupIterations, "iteration", "iterations")
+                                } by ${first.warmupTime} and ${first.measurementIterations} measurement ${
+                                    noun(first.measurementIterations, "iteration", "iterations")
+                                } by ${first.measurementTime}."
+                            )
 
                             appendLine()
                             appendLine("| Benchmark | Score |")
diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt
deleted file mode 100644
index d973ebae4..000000000
--- a/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * Copyright 2018-2022 KMath contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-@file:Suppress("KDocUnresolvedReference")
-
-package space.kscience.kmath.ejml.codegen
-
-import org.intellij.lang.annotations.Language
-import java.io.File
-
-private fun Appendable.appendEjmlVector(type: String, ejmlMatrixType: String) {
-    @Language("kotlin") val text = """/**
- * [EjmlVector] specialization for [$type].
- */
-public class Ejml${type}Vector<out M : $ejmlMatrixType>(override val origin: M) : EjmlVector<$type, M>(origin) {
-    init {
-        require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" }
-    }
-
-    override operator fun get(index: Int): $type = origin[0, index]
-}"""
-    appendLine(text)
-    appendLine()
-}
-
-private fun Appendable.appendEjmlMatrix(type: String, ejmlMatrixType: String) {
-    val text = """/**
- * [EjmlMatrix] specialization for [$type].
- */
-public class Ejml${type}Matrix<out M : $ejmlMatrixType>(override val origin: M) : EjmlMatrix<$type, M>(origin) {
-    override operator fun get(i: Int, j: Int): $type = origin[i, j]
-}"""
-    appendLine(text)
-    appendLine()
-}
-
-private fun Appendable.appendEjmlLinearSpace(
-    type: String,
-    kmathAlgebra: String,
-    ejmlMatrixParentTypeMatrix: String,
-    ejmlMatrixType: String,
-    ejmlMatrixDenseType: String,
-    ops: String,
-    denseOps: String,
-    isDense: Boolean,
-) {
-    @Language("kotlin") val text = """/**
- * [EjmlLinearSpace] implementation based on [CommonOps_$ops], [DecompositionFactory_${ops}] operations and
- * [${ejmlMatrixType}] matrices.
- */
-public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, $ejmlMatrixType>() {
-    /**
-     * The [${kmathAlgebra}] reference.
-     */
-    override val elementAlgebra: $kmathAlgebra get() = $kmathAlgebra
-
-    @Suppress("UNCHECKED_CAST")
-    override fun Matrix<${type}>.toEjml(): Ejml${type}Matrix<${ejmlMatrixType}> = when {
-        this is Ejml${type}Matrix<*> && origin is $ejmlMatrixType -> this as Ejml${type}Matrix<${ejmlMatrixType}>
-        else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) }
-    }
-
-    @Suppress("UNCHECKED_CAST")
-    override fun Point<${type}>.toEjml(): Ejml${type}Vector<${ejmlMatrixType}> = when {
-        this is Ejml${type}Vector<*> && origin is $ejmlMatrixType -> this as Ejml${type}Vector<${ejmlMatrixType}>
-        else -> Ejml${type}Vector(${ejmlMatrixType}(size, 1).also {
-            (0 until it.numRows).forEach { row -> it[row, 0] = get(row) }
-        })
-    }
-
-    override fun buildMatrix(
-        rows: Int,
-        columns: Int,
-        initializer: ${kmathAlgebra}.(i: Int, j: Int) -> ${type},
-    ): Ejml${type}Matrix<${ejmlMatrixType}> = ${ejmlMatrixType}(rows, columns).also {
-        (0 until rows).forEach { row ->
-            (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) }
-        }
-    }.wrapMatrix()
-
-    override fun buildVector(
-        size: Int,
-        initializer: ${kmathAlgebra}.(Int) -> ${type},
-    ): Ejml${type}Vector<${ejmlMatrixType}> = Ejml${type}Vector(${ejmlMatrixType}(size, 1).also {
-        (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) }
-    })
-
-    private fun <T : ${ejmlMatrixParentTypeMatrix}> T.wrapMatrix() = Ejml${type}Matrix(this)
-    private fun <T : ${ejmlMatrixParentTypeMatrix}> T.wrapVector() = Ejml${type}Vector(this)
-
-    override fun Matrix<${type}>.unaryMinus(): Matrix<${type}> = this * elementAlgebra { -one }
-
-    override fun Matrix<${type}>.dot(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> {
-        val out = ${ejmlMatrixType}(1, 1)
-        CommonOps_${ops}.mult(toEjml().origin, other.toEjml().origin, out)
-        return out.wrapMatrix()
-    }
-
-    override fun Matrix<${type}>.dot(vector: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> {
-        val out = ${ejmlMatrixType}(1, 1)
-        CommonOps_${ops}.mult(toEjml().origin, vector.toEjml().origin, out)
-        return out.wrapVector()
-    }
-
-    override operator fun Matrix<${type}>.minus(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> {
-        val out = ${ejmlMatrixType}(1, 1)
-
-        CommonOps_${ops}.add(
-            elementAlgebra.one, 
-            toEjml().origin, 
-            elementAlgebra { -one },
-            other.toEjml().origin, 
-            out,${
-        if (isDense) "" else
-            """
-            null, 
-            null,"""
-    }
-        )
-
-        return out.wrapMatrix()
-    }
-
-    override operator fun Matrix<${type}>.times(value: ${type}): Ejml${type}Matrix<${ejmlMatrixType}> {
-        val res = ${ejmlMatrixType}(1, 1)
-        CommonOps_${ops}.scale(value, toEjml().origin, res)
-        return res.wrapMatrix()
-    }
-
-    override fun Point<${type}>.unaryMinus(): Ejml${type}Vector<${ejmlMatrixType}> {
-        val res = ${ejmlMatrixType}(1, 1)
-        CommonOps_${ops}.changeSign(toEjml().origin, res)
-        return res.wrapVector()
-    }
-
-    override fun Matrix<${type}>.plus(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> {
-        val out = ${ejmlMatrixType}(1, 1)
-        
-        CommonOps_${ops}.add(
-            elementAlgebra.one,
-            toEjml().origin,
-            elementAlgebra.one,
-            other.toEjml().origin, 
-            out,${
-        if (isDense) "" else
-            """
-            null, 
-            null,"""
-    }
-        )
-
-        return out.wrapMatrix()
-    }
-
-    override fun Point<${type}>.plus(other: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> {
-        val out = ${ejmlMatrixType}(1, 1)
-
-        CommonOps_${ops}.add(
-            elementAlgebra.one,
-            toEjml().origin,
-            elementAlgebra.one,
-            other.toEjml().origin,
-            out,${
-        if (isDense) "" else
-            """
-            null, 
-            null,"""
-    }
-        )
-
-        return out.wrapVector()
-    }
-
-    override fun Point<${type}>.minus(other: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> {
-        val out = ${ejmlMatrixType}(1, 1)
-
-        CommonOps_${ops}.add(
-            elementAlgebra.one,
-            toEjml().origin,
-            elementAlgebra { -one },
-            other.toEjml().origin,
-            out,${
-        if (isDense) "" else
-            """
-            null, 
-            null,"""
-    }
-        )
-
-        return out.wrapVector()
-    }
-
-    override fun ${type}.times(m: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> = m * this
-
-    override fun Point<${type}>.times(value: ${type}): Ejml${type}Vector<${ejmlMatrixType}> {
-        val res = ${ejmlMatrixType}(1, 1)
-        CommonOps_${ops}.scale(value, toEjml().origin, res)
-        return res.wrapVector()
-    }
-
-    override fun ${type}.times(v: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> = v * this
-
-    @UnstableKMathAPI
-    override fun <F : StructureFeature> computeFeature(structure: Matrix<${type}>, type: KClass<out F>): F? {
-        structure.getFeature(type)?.let { return it }
-        val origin = structure.toEjml().origin
-
-        return when (type) {
-        ${
-        if (isDense)
-            """    InverseMatrixFeature::class -> object : InverseMatrixFeature<${type}> {
-                override val inverse: Matrix<${type}> by lazy {
-                    val res = origin.copy()
-                    CommonOps_${ops}.invert(res)
-                    res.wrapMatrix()
-                }
-            }
-
-            DeterminantFeature::class -> object : DeterminantFeature<${type}> {
-                override val determinant: $type by lazy { CommonOps_${ops}.det(origin) }
-            }
-
-            SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature<${type}> {
-                private val svd by lazy {
-                    DecompositionFactory_${ops}.svd(origin.numRows, origin.numCols, true, true, false)
-                        .apply { decompose(origin.copy()) }
-                }
-
-                override val u: Matrix<${type}> by lazy { svd.getU(null, false).wrapMatrix() }
-                override val s: Matrix<${type}> by lazy { svd.getW(null).wrapMatrix() }
-                override val v: Matrix<${type}> by lazy { svd.getV(null, false).wrapMatrix() }
-                override val singularValues: Point<${type}> by lazy { ${type}Buffer(svd.singularValues) }
-            }
-
-            QRDecompositionFeature::class -> object : QRDecompositionFeature<${type}> {
-                private val qr by lazy {
-                    DecompositionFactory_${ops}.qr().apply { decompose(origin.copy()) }
-                }
-
-                override val q: Matrix<${type}> by lazy {
-                    qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature)
-                }
-
-                override val r: Matrix<${type}> by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) }
-            }
-
-            CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<${type}> {
-                override val l: Matrix<${type}> by lazy {
-                    val cholesky =
-                        DecompositionFactory_${ops}.chol(structure.rowNum, true).apply { decompose(origin.copy()) }
-
-                    cholesky.getT(null).wrapMatrix().withFeature(LFeature)
-                }
-            }
-
-            LupDecompositionFeature::class -> object : LupDecompositionFeature<${type}> {
-                private val lup by lazy {
-                    DecompositionFactory_${ops}.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) }
-                }
-
-                override val l: Matrix<${type}> by lazy {
-                    lup.getLower(null).wrapMatrix().withFeature(LFeature)
-                }
-
-                override val u: Matrix<${type}> by lazy {
-                    lup.getUpper(null).wrapMatrix().withFeature(UFeature)
-                }
-
-                override val p: Matrix<${type}> by lazy { lup.getRowPivot(null).wrapMatrix() }
-            }""" else """    QRDecompositionFeature::class -> object : QRDecompositionFeature<$type> {
-                private val qr by lazy {
-                    DecompositionFactory_${ops}.qr(FillReducing.NONE).apply { decompose(origin.copy()) }
-                }
-
-                override val q: Matrix<${type}> by lazy {
-                    qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature)
-                }
-
-                override val r: Matrix<${type}> by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) }
-            }
-
-            CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<${type}> {
-                override val l: Matrix<${type}> by lazy {
-                    val cholesky =
-                        DecompositionFactory_${ops}.cholesky().apply { decompose(origin.copy()) }
-
-                    (cholesky.getT(null) as ${ejmlMatrixParentTypeMatrix}).wrapMatrix().withFeature(LFeature)
-                }
-            }
-
-            LUDecompositionFeature::class, DeterminantFeature::class, InverseMatrixFeature::class -> object :
-                LUDecompositionFeature<${type}>, DeterminantFeature<${type}>, InverseMatrixFeature<${type}> {
-                private val lu by lazy {
-                    DecompositionFactory_${ops}.lu(FillReducing.NONE).apply { decompose(origin.copy()) }
-                }
-
-                override val l: Matrix<${type}> by lazy {
-                    lu.getLower(null).wrapMatrix().withFeature(LFeature)
-                }
-
-                override val u: Matrix<${type}> by lazy {
-                    lu.getUpper(null).wrapMatrix().withFeature(UFeature)
-                }
-
-                override val inverse: Matrix<${type}> by lazy {
-                    var a = origin
-                    val inverse = ${ejmlMatrixDenseType}(1, 1)
-                    val solver = LinearSolverFactory_${ops}.lu(FillReducing.NONE)
-                    if (solver.modifiesA()) a = a.copy()
-                    val i = CommonOps_${denseOps}.identity(a.numRows)
-                    solver.solve(i, inverse)
-                    inverse.wrapMatrix()
-                }
-
-                override val determinant: $type by lazy { elementAlgebra.number(lu.computeDeterminant().real) }
-            }"""
-    }
-
-            else -> null
-        }?.let{
-            type.cast(it)
-        }
-    }
-
-    /**
-     * Solves for *x* in the following equation: *x = [a] <sup>-1</sup> &middot; [b]*.
-     *
-     * @param a the base matrix.
-     * @param b n by p matrix.
-     * @return the solution for *x* that is n by p.
-     */
-    public fun solve(a: Matrix<${type}>, b: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> {
-        val res = ${ejmlMatrixType}(1, 1)
-        CommonOps_${ops}.solve(${ejmlMatrixType}(a.toEjml().origin), ${ejmlMatrixType}(b.toEjml().origin), res)
-        return res.wrapMatrix()
-    }
-
-    /**
-     * Solves for *x* in the following equation: *x = [a] <sup>-1</sup> &middot; [b]*.
-     *
-     * @param a the base matrix.
-     * @param b n by p vector.
-     * @return the solution for *x* that is n by p.
-     */
-    public fun solve(a: Matrix<${type}>, b: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> {
-        val res = ${ejmlMatrixType}(1, 1)
-        CommonOps_${ops}.solve(${ejmlMatrixType}(a.toEjml().origin), ${ejmlMatrixType}(b.toEjml().origin), res)
-        return Ejml${type}Vector(res)
-    }
-}"""
-    appendLine(text)
-    appendLine()
-}
-
-
-/**
- * Generates routine EJML classes.
- */
-fun ejmlCodegen(outputFile: String): Unit = File(outputFile).run {
-    parentFile.mkdirs()
-
-    writer().use {
-        it.appendLine("/*")
-        it.appendLine(" * Copyright 2018-2021 KMath contributors.")
-        it.appendLine(" * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.")
-        it.appendLine(" */")
-        it.appendLine()
-        it.appendLine("/* This file is generated with buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt */")
-        it.appendLine()
-        it.appendLine("package space.kscience.kmath.ejml")
-        it.appendLine()
-        it.appendLine("""import org.ejml.data.*
-import org.ejml.dense.row.CommonOps_DDRM
-import org.ejml.dense.row.CommonOps_FDRM
-import org.ejml.dense.row.factory.DecompositionFactory_DDRM
-import org.ejml.dense.row.factory.DecompositionFactory_FDRM
-import org.ejml.sparse.FillReducing
-import org.ejml.sparse.csc.CommonOps_DSCC
-import org.ejml.sparse.csc.CommonOps_FSCC
-import org.ejml.sparse.csc.factory.DecompositionFactory_DSCC
-import org.ejml.sparse.csc.factory.DecompositionFactory_FSCC
-import org.ejml.sparse.csc.factory.LinearSolverFactory_DSCC
-import org.ejml.sparse.csc.factory.LinearSolverFactory_FSCC
-import space.kscience.kmath.linear.*
-import space.kscience.kmath.linear.Matrix
-import space.kscience.kmath.UnstableKMathAPI
-import space.kscience.kmath.nd.StructureFeature
-import space.kscience.kmath.operations.DoubleField
-import space.kscience.kmath.operations.FloatField
-import space.kscience.kmath.operations.invoke
-import space.kscience.kmath.structures.DoubleBuffer
-import space.kscience.kmath.structures.FloatBuffer
-import kotlin.reflect.KClass
-import kotlin.reflect.cast""")
-        it.appendLine()
-        it.appendEjmlVector("Double", "DMatrix")
-        it.appendEjmlVector("Float", "FMatrix")
-        it.appendEjmlMatrix("Double", "DMatrix")
-        it.appendEjmlMatrix("Float", "FMatrix")
-        it.appendEjmlLinearSpace("Double", "DoubleField", "DMatrix", "DMatrixRMaj", "DMatrixRMaj", "DDRM", "DDRM", true)
-        it.appendEjmlLinearSpace("Float", "FloatField", "FMatrix", "FMatrixRMaj", "FMatrixRMaj", "FDRM", "FDRM", true)
-
-        it.appendEjmlLinearSpace(
-            type = "Double",
-            kmathAlgebra = "DoubleField",
-            ejmlMatrixParentTypeMatrix = "DMatrix",
-            ejmlMatrixType = "DMatrixSparseCSC",
-            ejmlMatrixDenseType = "DMatrixRMaj",
-            ops = "DSCC",
-            denseOps = "DDRM",
-            isDense = false,
-        )
-
-        it.appendEjmlLinearSpace(
-            type = "Float",
-            kmathAlgebra = "FloatField",
-            ejmlMatrixParentTypeMatrix = "FMatrix",
-            ejmlMatrixType = "FMatrixSparseCSC",
-            ejmlMatrixDenseType = "FMatrixRMaj",
-            ops = "FSCC",
-            denseOps = "FDRM",
-            isDense = false,
-        )
-    }
-}
diff --git a/docs/buffers.md b/docs/buffers.md
index e7573497e..ab8bf6a77 100644
--- a/docs/buffers.md
+++ b/docs/buffers.md
@@ -17,4 +17,4 @@ own `MemoryBuffer.create()` factory).
 ## Buffer performance
 
 One should avoid using default boxing buffer wherever it is possible. Try to use primitive buffers or memory buffers
-instead  .
+instead.
diff --git a/docs/codestyle.md b/docs/codestyle.md
index 73ba5f754..fb18e5103 100644
--- a/docs/codestyle.md
+++ b/docs/codestyle.md
@@ -1,27 +1,35 @@
 # Coding Conventions
 
-Generally, KMath code follows general [Kotlin coding conventions](https://kotlinlang.org/docs/reference/coding-conventions.html), but with a number of small changes and clarifications.
+Generally, KMath code follows
+general [Kotlin coding conventions](https://kotlinlang.org/docs/reference/coding-conventions.html), but with a number of
+small changes and clarifications.
 
 ## Utility Class Naming
 
-Filename should coincide with a name of one of the classes contained in the file or start with small letter and describe its contents.
+Filename should coincide with a name of one of the classes contained in the file or start with small letter and describe
+its contents.
 
-The code convention [here](https://kotlinlang.org/docs/reference/coding-conventions.html#source-file-names) says that file names should start with a capital letter even if file does not contain classes. Yet starting utility classes and aggregators with a small letter seems to be a good way to visually separate those files.
+The code convention [here](https://kotlinlang.org/docs/reference/coding-conventions.html#source-file-names) says that
+file names should start with a capital letter even if file does not contain classes. Yet starting utility classes and
+aggregators with a small letter seems to be a good way to visually separate those files.
 
 This convention could be changed in future in a non-breaking way.
 
 ## Private Variable Naming
 
-Private variables' names may start with underscore `_` for of the private mutable variable is shadowed by the public read-only value with the same meaning.
+Private variables' names may start with underscore `_` for of the private mutable variable is shadowed by the public
+read-only value with the same meaning.
 
-This rule does not permit underscores in names, but it is sometimes useful to "underscore" the fact that public and private versions draw up the same entity. It is allowed only for private variables.
+This rule does not permit underscores in names, but it is sometimes useful to "underscore" the fact that public and
+private versions draw up the same entity. It is allowed only for private variables.
 
 This convention could be changed in future in a non-breaking way.
 
 ## Functions and Properties One-liners
 
-Use one-liners when they occupy single code window line both for functions and properties with getters like 
-`val b: String get() = "fff"`. The same should be performed with multiline expressions when they could be 
+Use one-liners when they occupy single code window line both for functions and properties with getters like
+`val b: String get() = "fff"`. The same should be performed with multiline expressions when they could be
 cleanly separated.
 
-There is no universal consensus whenever use `fun a() = ...` or `fun a() { return ... }`. Yet from reader outlook one-lines seem to better show that the property or function is easily calculated.
+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.
diff --git a/docs/expressions.md b/docs/expressions.md
index e6250110c..cb9deca45 100644
--- a/docs/expressions.md
+++ b/docs/expressions.md
@@ -1,21 +1,24 @@
 # Expressions
 
-Expressions is a feature, which allows constructing lazily or immediately calculated parametric mathematical expressions.
+Expressions is a feature, which allows constructing lazily or immediately calculated parametric mathematical
+expressions.
 
 The potential use-cases for it (so far) are following:
 
 * lazy evaluation (in general simple lambda is better, but there are some border cases);
 * automatic differentiation in single-dimension and in multiple dimensions;
 * generation of mathematical syntax trees with subsequent code generation for other languages;
-* symbolic computations, especially differentiation (and some other actions with `kmath-symja` integration with Symja's `IExpr`&mdash;integration, simplification, and more);
+* symbolic computations, especially differentiation (and some other actions with `kmath-symja` integration with
+  Symja's `IExpr`&mdash;integration, simplification, and more);
 * visualization with `kmath-jupyter`.
 
-The workhorse of this API is `Expression` interface, which exposes single `operator fun invoke(arguments: Map<Symbol, T>): T`
+The workhorse of this API is `Expression` interface, which exposes
+single `operator fun invoke(arguments: Map<Symbol, T>): T`
 method. `ExpressionAlgebra` is used to generate expressions and introduce variables.
 
 Currently there are two implementations:
 
 * Generic `ExpressionField` in `kmath-core` which allows construction of custom lazy expressions
 
-* Auto-differentiation expression in `kmath-commons` module allows using full power of `DerivativeStructure` 
-from commons-math. **TODO: add example**
+* Auto-differentiation expression in `kmath-commons` module allows using full power of `DerivativeStructure`
+  from commons-math. **TODO: add example**
diff --git a/docs/images/KM.svg b/docs/images/KM.svg
index 55a4339b1..f9003c5bb 100644
--- a/docs/images/KM.svg
+++ b/docs/images/KM.svg
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <!--
-  - Copyright 2018-2022 KMath contributors.
+  - Copyright 2018-2024 KMath contributors.
   - Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
   -->
 
diff --git a/docs/images/KM_mono.svg b/docs/images/KM_mono.svg
index f1194f887..057968d0e 100644
--- a/docs/images/KM_mono.svg
+++ b/docs/images/KM_mono.svg
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <!--
-  - Copyright 2018-2022 KMath contributors.
+  - Copyright 2018-2024 KMath contributors.
   - Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
   -->
 
diff --git a/docs/images/KMath.svg b/docs/images/KMath.svg
index 509a184bc..4e1e8a783 100644
--- a/docs/images/KMath.svg
+++ b/docs/images/KMath.svg
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <!--
-  - Copyright 2018-2022 KMath contributors.
+  - Copyright 2018-2024 KMath contributors.
   - Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
   -->
 
diff --git a/docs/images/KMath_mono.svg b/docs/images/KMath_mono.svg
index e781979e2..5b93d45b7 100644
--- a/docs/images/KMath_mono.svg
+++ b/docs/images/KMath_mono.svg
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <!--
-  - Copyright 2018-2022 KMath contributors.
+  - Copyright 2018-2024 KMath contributors.
   - Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
   -->
 
diff --git a/docs/linear.md b/docs/linear.md
index 2a05499ef..3ded92ffe 100644
--- a/docs/linear.md
+++ b/docs/linear.md
@@ -1,8 +1,12 @@
 ## Basic linear algebra layout
 
-KMath support for linear algebra organized in a context-oriented way, which means that operations are in most cases declared in context classes, and are not the members of classes that store data. This allows more flexible approach to maintain multiple back-ends. The new operations added as extensions to contexts instead of being member functions of data structures.
+KMath support for linear algebra organized in a context-oriented way, which means that operations are in most cases
+declared in context classes, and are not the members of classes that store data. This allows more flexible approach to
+maintain multiple back-ends. The new operations added as extensions to contexts instead of being member functions of
+data structures.
 
-The main context for linear algebra over matrices and vectors is `LinearSpace`, which defines addition and dot products of matrices and vectors:
+The main context for linear algebra over matrices and vectors is `LinearSpace`, which defines addition and dot products
+of matrices and vectors:
 
 ```kotlin
 import space.kscience.kmath.linear.*
@@ -28,4 +32,5 @@ LinearSpace.Companion.real {
 ## Backends overview
 
 ### EJML
+
 ### Commons Math
diff --git a/docs/nd-structure.md b/docs/nd-structure.md
index 3e9203ec0..8f2e504db 100644
--- a/docs/nd-structure.md
+++ b/docs/nd-structure.md
@@ -8,6 +8,7 @@ One of the most sought after features of mathematical libraries is the high-perf
 structures. In `kmath` performance depends on which particular context was used for operation.
 
 Let us consider following contexts:
+
 ```kotlin
     // automatically build context most suited for given type.
     val autoField = NDField.auto(DoubleField, dim, dim)
@@ -16,6 +17,7 @@ Let us consider following contexts:
     //A generic boxing field. It should be used for objects, not primitives.
     val genericField = NDField.buffered(DoubleField, dim, dim)
 ```
+
 Now let us perform several tests and see, which implementation is best suited for each case:
 
 ## Test case
@@ -24,7 +26,9 @@ To test performance we will take 2d-structures with `dim = 1000` and add a struc
 to it `n = 1000` times.
 
 ## Specialized
+
 The code to run this looks like:
+
 ```kotlin
     specializedField.run {
         var res: NDBuffer<Double> = one
@@ -33,13 +37,16 @@ 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
 with doubles. We will measure everything else relative to this one, so time for this test will be `1x` (real time
 on my computer is about 4.5 seconds). The only problem with this approach is that it requires specifying type
 from the beginning. Everyone does so anyway, so it is the recommended approach.
 
 ## Automatic
+
 Let's do the same with automatic field inference:
+
 ```kotlin
     autoField.run {
         var res = one
@@ -48,13 +55,16 @@ 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
 returns the same `RealNDField` in this case. Of course, it is usually better to use specialized method to be sure.
 
 ## Lazy
+
 Lazy field does not produce a structure when asked, instead it generates an empty structure and fills it on-demand
 using coroutines to parallelize computations.
 When one calls
+
 ```kotlin
     lazyField.run {
         var res = one
@@ -63,12 +73,14 @@ When one calls
         }
     }
 ```
+
 The result will be calculated almost immediately but the result will be empty. To get the full result
 structure one needs to call all its elements. In this case computation overhead will be huge. So this field never
 should be used if one expects to use the full result structure. Though if one wants only small fraction, it could
 save a lot of time.
 
 This field still could be used with reasonable performance if call code is changed:
+
 ```kotlin
     lazyField.run {
         val res = one.map {
@@ -82,10 +94,13 @@ This field still could be used with reasonable performance if call code is chang
         res.elements().forEach { it.second }
     }
 ```
+
 In this case it completes in about `4x-5x` time due to boxing.
 
 ## Boxing
+
 The boxing field produced by
+
 ```kotlin
     genericField.run {
         var res: NDBuffer<Double> = one
@@ -94,18 +109,22 @@ The boxing field produced by
         }
     }
 ```
+
 is the slowest one, because it requires boxing and unboxing the `double` on each operation. It takes about
 `15x` time (**TODO: there seems to be a problem here, it should be slow, but not that slow**). This field should
 never be used for primitives.
 
 ## Element operation
+
 Let us also check the speed for direct operations on elements:
+
 ```kotlin
     var res = genericField.one
     repeat(n) {
         res += 1.0
     }
 ```
+
 One would expect to be at least as slow as field operation, but in fact, this one takes only `2x` time to complete.
 It happens, because in this particular case it does not use actual `NDField` but instead calculated directly
 via extension function.
@@ -114,6 +133,7 @@ via extension function.
 
 Usually it is bad idea to compare the direct numerical operation performance in different languages, but it hard to
 work completely without frame of reference. In this case, simple numpy code:
+
 ```python
 import numpy as np
 
@@ -121,7 +141,9 @@ res = np.ones((1000,1000))
 for i in range(1000):
     res = res + 1.0
 ```
-gives the completion time of about `1.1x`, which means that specialized kotlin code in fact is working faster (I think it is
+
+gives the completion time of about `1.1x`, which means that specialized kotlin code in fact is working faster (I think
+it is
 because better memory management). Of course if one writes `res += 1.0`, the performance will be different,
 but it would be different case, because numpy overrides `+=` with in-place operations. In-place operations are
 available in `kmath` with `MutableNDStructure` but there is no field for it (one can still work with mapping
diff --git a/docs/polynomials.md b/docs/polynomials.md
index b255acda1..5fdce0a91 100644
--- a/docs/polynomials.md
+++ b/docs/polynomials.md
@@ -1,27 +1,54 @@
 # Polynomials and Rational Functions
 
-KMath provides a way to work with uni- and multivariate polynomials and rational functions. It includes full support of arithmetic operations of integers, **constants** (elements of ring polynomials are build over), variables (for certain multivariate implementations), polynomials and rational functions encapsulated in so-called **polynomial space** and **rational function space** and some other utilities such as algebraic differentiation and substitution.
+KMath provides a way to work with uni- and multivariate polynomials and rational functions. It includes full support of
+arithmetic operations of integers, **constants** (elements of ring polynomials are build over), variables (for certain
+multivariate implementations), polynomials and rational functions encapsulated in so-called **polynomial space** and *
+*rational function space** and some other utilities such as algebraic differentiation and substitution.
 
 ## Concrete realizations
 
 There are 3 approaches to represent polynomials:
-1. For univariate polynomials one can represent and store polynomial as a list of coefficients for each power of the variable. I.e. polynomial  $a_0 + \dots + a_n x^n $ can be represented as a finite sequence $(a_0; \dots; a_n)$. (Compare to sequential definition of polynomials.)
-2. For multivariate polynomials one can represent and store polynomial as a matching (in programming it is called "map" or "dictionary", in math it is called [functional relation](https://en.wikipedia.org/wiki/Binary_relation#Special_types_of_binary_relations)) of each "**term signature**" (that describes what variables and in what powers appear in the term) with corresponding coefficient of the term. But there are 2 possible approaches of term signature representation:
-   1. One can number all the variables, so term signature can be represented as a sequence describing powers of the variables. I.e. signature of term  $c \\; x_0^{d_0} \dots x_n^{d_n} $ (for natural or zero  $d_i $) can be represented as a finite sequence  $(d_0; \dots; d_n)$.
-   2. One can represent variables as objects ("**labels**"), so term signature can be also represented as a matching of each appeared variable with its power in the term. I.e. signature of term  $c \\; x_0^{d_0} \dots x_n^{d_n} $ (for natural non-zero  $d_i $) can be represented as a finite matching  $(x_0 \to d_1; \dots; x_n \to d_n)$.
 
-All that three approaches are implemented by "list", "numbered", and "labeled" versions of polynomials and polynomial spaces respectively. Whereas all rational functions are represented as fractions with corresponding polynomial numerator and denominator, and rational functions' spaces are implemented in the same way as usual field of rational numbers (or more precisely, as any field of fractions over integral domain) should be implemented.
+1. For univariate polynomials one can represent and store polynomial as a list of coefficients for each power of the
+   variable. I.e. polynomial $a_0 + \dots + a_n x^n $ can be represented as a finite sequence $(a_0; \dots; a_n)$. (
+   Compare to sequential definition of polynomials.)
+2. For multivariate polynomials one can represent and store polynomial as a matching (in programming it is called "map"
+   or "dictionary", in math it is
+   called [functional relation](https://en.wikipedia.org/wiki/Binary_relation#Special_types_of_binary_relations)) of
+   each "**term signature**" (that describes what variables and in what powers appear in the term) with corresponding
+   coefficient of the term. But there are 2 possible approaches of term signature representation:
+    1. One can number all the variables, so term signature can be represented as a sequence describing powers of the
+       variables. I.e. signature of term $c \\; x_0^{d_0} \dots x_n^{d_n} $ (for natural or zero $d_i $) can be
+       represented as a finite sequence $(d_0; \dots; d_n)$.
+    2. One can represent variables as objects ("**labels**"), so term signature can be also represented as a matching of
+       each appeared variable with its power in the term. I.e. signature of term $c \\; x_0^{d_0} \dots x_n^{d_n} $ (for
+       natural non-zero $d_i $) can be represented as a finite matching $(x_0 \to d_1; \dots; x_n \to d_n)$.
+
+All that three approaches are implemented by "list", "numbered", and "labeled" versions of polynomials and polynomial
+spaces respectively. Whereas all rational functions are represented as fractions with corresponding polynomial numerator
+and denominator, and rational functions' spaces are implemented in the same way as usual field of rational numbers (or
+more precisely, as any field of fractions over integral domain) should be implemented.
 
 So here are a bit of details. Let `C` by type of constants. Then:
-1. `ListPolynomial`, `ListPolynomialSpace`, `ListRationalFunction` and `ListRationalFunctionSpace` implement the first scenario. `ListPolynomial` stores polynomial  $a_0 + \dots + a_n x^n $ as a coefficients list `listOf(a_0, ..., a_n)` (of type `List<C>`).
-  
-   They also have variation `ScalableListPolynomialSpace` that replaces former polynomials and implements `ScaleOperations`.
-2. `NumberedPolynomial`, `NumberedPolynomialSpace`, `NumberedRationalFunction` and `NumberedRationalFunctionSpace` implement second scenario. `NumberedPolynomial` stores polynomials as structures of type `Map<List<UInt>, C>`. Signatures are stored as `List<UInt>`. To prevent ambiguity signatures should not end with zeros.
-3. `LabeledPolynomial`, `LabeledPolynomialSpace`, `LabeledRationalFunction` and `LabeledRationalFunctionSpace` implement third scenario using common `Symbol` as variable type. `LabeledPolynomial` stores polynomials as structures of type `Map<Map<Symbol, UInt>, C>`. Signatures are stored as `Map<Symbol, UInt>`. To prevent ambiguity each signature should not map any variable to zero.
+
+1. `ListPolynomial`, `ListPolynomialSpace`, `ListRationalFunction` and `ListRationalFunctionSpace` implement the first
+   scenario. `ListPolynomial` stores polynomial $a_0 + \dots + a_n x^n $ as a coefficients
+   list `listOf(a_0, ..., a_n)` (of type `List<C>`).
+
+   They also have variation `ScalableListPolynomialSpace` that replaces former polynomials and
+   implements `ScaleOperations`.
+2. `NumberedPolynomial`, `NumberedPolynomialSpace`, `NumberedRationalFunction` and `NumberedRationalFunctionSpace`
+   implement second scenario. `NumberedPolynomial` stores polynomials as structures of type `Map<List<UInt>, C>`.
+   Signatures are stored as `List<UInt>`. To prevent ambiguity signatures should not end with zeros.
+3. `LabeledPolynomial`, `LabeledPolynomialSpace`, `LabeledRationalFunction` and `LabeledRationalFunctionSpace` implement
+   third scenario using common `Symbol` as variable type. `LabeledPolynomial` stores polynomials as structures of
+   type `Map<Map<Symbol, UInt>, C>`. Signatures are stored as `Map<Symbol, UInt>`. To prevent ambiguity each signature
+   should not map any variable to zero.
 
 ### Example: `ListPolynomial`
 
-For example, polynomial  $2 - 3x + x^2 $ (with `Int` coefficients) is represented
+For example, polynomial $2 - 3x + x^2 $ (with `Int` coefficients) is represented
+
 ```kotlin
 val polynomial: ListPolynomial<Int> = ListPolynomial(listOf(2, -3, 1))
 // or
@@ -29,6 +56,7 @@ val polynomial: ListPolynomial<Int> = ListPolynomial(2, -3, 1)
 ```
 
 All algebraic operations can be used in corresponding space:
+
 ```kotlin
 val computationResult = Int.algebra.listPolynomialSpace {
    ListPolynomial(2, -3, 1) + ListPolynomial(0, 6) == ListPolynomial(2, 3, 1)
@@ -41,7 +69,8 @@ For more see [examples](../examples/src/main/kotlin/space/kscience/kmath/functio
 
 ### Example: `NumberedPolynomial`
 
-For example, polynomial  $3 + 5 x_1 - 7 x_0^2 x_2 $ (with `Int` coefficients) is represented
+For example, polynomial $3 + 5 x_1 - 7 x_0^2 x_2 $ (with `Int` coefficients) is represented
+
 ```kotlin
 val polynomial: NumberedPolynomial<Int> = NumberedPolynomial(
    mapOf(
@@ -59,6 +88,7 @@ val polynomial: NumberedPolynomial<Int> = NumberedPolynomial(
 ```
 
 All algebraic operations can be used in corresponding space:
+
 ```kotlin
 val computationResult = Int.algebra.numberedPolynomialSpace {
    NumberedPolynomial(
@@ -83,7 +113,8 @@ For more see [examples](../examples/src/main/kotlin/space/kscience/kmath/functio
 
 ### Example: `LabeledPolynomial`
 
-For example, polynomial  $3 + 5 y - 7 x^2 z $ (with `Int` coefficients) is represented
+For example, polynomial $3 + 5 y - 7 x^2 z $ (with `Int` coefficients) is represented
+
 ```kotlin
 val polynomial: LabeledPolynomial<Int> = LabeledPolynomial(
    mapOf(
@@ -101,6 +132,7 @@ val polynomial: LabeledPolynomial<Int> = LabeledPolynomial(
 ```
 
 All algebraic operations can be used in corresponding space:
+
 ```kotlin
 val computationResult = Int.algebra.labeledPolynomialSpace {
    LabeledPolynomial(
@@ -150,23 +182,42 @@ classDiagram
    PolynomialSpaceOfFractions <|-- MultivariatePolynomialSpaceOfFractions
 ```
 
-There are implemented `Polynomial` and `RationalFunction` interfaces as abstractions of polynomials and rational functions respectively (although, there is not a lot of logic in them) and `PolynomialSpace` and `RationalFunctionSpace` (that implement `Ring` interface) as abstractions of polynomials' and rational functions' spaces respectively. More precisely, that means they allow to declare common logic of interaction with such objects and spaces:
+There are implemented `Polynomial` and `RationalFunction` interfaces as abstractions of polynomials and rational
+functions respectively (although, there is not a lot of logic in them) and `PolynomialSpace`
+and `RationalFunctionSpace` (that implement `Ring` interface) as abstractions of polynomials' and rational functions'
+spaces respectively. More precisely, that means they allow to declare common logic of interaction with such objects and
+spaces:
+
 - `Polynomial` does not provide any logic. It is marker interface.
 - `RationalFunction` provides numerator and denominator of rational function and destructuring declaration for them.
-- `PolynomialSpace` provides all possible arithmetic interactions of integers, constants (of type `C`), and polynomials (of type `P`) like addition, subtraction, multiplication, and some others and common properties like degree of polynomial.
-- `RationalFunctionSpace` provides the same as `PolynomialSpace` but also for rational functions: all possible arithmetic interactions of integers, constants (of type `C`), polynomials (of type `P`), and rational functions (of type `R`) like addition, subtraction, multiplication, division (in some cases), and some others and common properties like degree of polynomial.
+- `PolynomialSpace` provides all possible arithmetic interactions of integers, constants (of type `C`), and
+  polynomials (of type `P`) like addition, subtraction, multiplication, and some others and common properties like
+  degree of polynomial.
+- `RationalFunctionSpace` provides the same as `PolynomialSpace` but also for rational functions: all possible
+  arithmetic interactions of integers, constants (of type `C`), polynomials (of type `P`), and rational functions (of
+  type `R`) like addition, subtraction, multiplication, division (in some cases), and some others and common properties
+  like degree of polynomial.
 
-Then to add abstraction of similar behaviour with variables (in multivariate case) there are implemented `MultivariatePolynomialSpace` and `MultivariateRationalFunctionSpace`. They just include variables (of type `V`) in the interactions of the entities.
+Then to add abstraction of similar behaviour with variables (in multivariate case) there are
+implemented `MultivariatePolynomialSpace` and `MultivariateRationalFunctionSpace`. They just include variables (of
+type `V`) in the interactions of the entities.
 
 Also, to remove boilerplates there were provided helping subinterfaces and abstract subclasses:
-- `PolynomialSpaceOverRing` allows to replace implementation of interactions of integers and constants with implementations from provided ring over constants (of type `A: Ring<C>`).
+
+- `PolynomialSpaceOverRing` allows to replace implementation of interactions of integers and constants with
+  implementations from provided ring over constants (of type `A: Ring<C>`).
 - `RationalFunctionSpaceOverRing` &mdash; the same but for `RationalFunctionSpace`.
-- `RationalFunctionSpaceOverPolynomialSpace` &mdash; the same but "the inheritance" includes interactions with polynomials from provided `PolynomialSpace`.
-- `PolynomialSpaceOfFractions` is actually abstract subclass of `RationalFunctionSpace` that implements all fractions boilerplates with provided (`protected`) constructor of rational functions by polynomial numerator and denominator.
-- `MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace` and `MultivariatePolynomialSpaceOfFractions` &mdash; the same stories of operators inheritance and fractions boilerplates respectively but in multivariate case.
+- `RationalFunctionSpaceOverPolynomialSpace` &mdash; the same but "the inheritance" includes interactions with
+  polynomials from provided `PolynomialSpace`.
+- `PolynomialSpaceOfFractions` is actually abstract subclass of `RationalFunctionSpace` that implements all fractions
+  boilerplates with provided (`protected`) constructor of rational functions by polynomial numerator and denominator.
+- `MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace` and `MultivariatePolynomialSpaceOfFractions`
+  &mdash; the same stories of operators inheritance and fractions boilerplates respectively but in multivariate case.
 
 ## Utilities
 
-For all kinds of polynomials there are provided (implementation details depend on kind of polynomials) such common utilities as:
+For all kinds of polynomials there are provided (implementation details depend on kind of polynomials) such common
+utilities as:
+
 1. differentiation and anti-differentiation,
 2. substitution, invocation and functional representation.
\ No newline at end of file
diff --git a/docs/templates/ARTIFACT-TEMPLATE.md b/docs/templates/ARTIFACT-TEMPLATE.md
index a3e47e693..f6f37dcef 100644
--- a/docs/templates/ARTIFACT-TEMPLATE.md
+++ b/docs/templates/ARTIFACT-TEMPLATE.md
@@ -3,25 +3,11 @@
 The Maven coordinates of this project are `${group}:${name}:${version}`.
 
 **Gradle:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-    // development and snapshot versions
-    maven { url 'https://maven.pkg.jetbrains.space/spc/p/sci/dev' }
-}
 
-dependencies {
-    implementation '${group}:${name}:${version}'
-}
-```
-**Gradle Kotlin DSL:**
 ```kotlin
 repositories {
     maven("https://repo.kotlin.link")
     mavenCentral()
-    // development and snapshot versions
-    maven("https://maven.pkg.jetbrains.space/spc/p/sci/dev")
 }
 
 dependencies {
diff --git a/docs/templates/README-TEMPLATE.md b/docs/templates/README-TEMPLATE.md
index d7d5a806d..0844500ea 100644
--- a/docs/templates/README-TEMPLATE.md
+++ b/docs/templates/README-TEMPLATE.md
@@ -11,18 +11,22 @@ analog to Python's NumPy library. Later we found that kotlin is much more flexib
 architecture designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like
 experience could be achieved with [kmath-for-real](/kmath-for-real) extension module.
 
-[Documentation site (**WIP**)](https://SciProgCentre.github.io/kmath/)
+[Documentation site](https://SciProgCentre.github.io/kmath/)
 
 ## Publications and talks
 
 * [A conceptual article about context-oriented design](https://proandroiddev.com/an-introduction-context-oriented-programming-in-kotlin-2e79d316b0a2)
 * [Another article about context-oriented design](https://proandroiddev.com/diving-deeper-into-context-oriented-programming-in-kotlin-3ecb4ec38814)
 * [ACAT 2019 conference paper](https://aip.scitation.org/doi/abs/10.1063/1.5130103)
+* [A talk at KotlinConf 2019 about using kotlin for science](https://youtu.be/LI_5TZ7tnOE?si=4LknX41gl_YeUbIe)
+* [A talk on architecture at Joker-2021 (in Russian)](https://youtu.be/1bZ2doHiRRM?si=9w953ro9yu98X_KJ)
+* [The same talk in English](https://youtu.be/yP5DIc2fVwQ?si=louZzQ1dcXV6gP10)
+* [A seminar on tensor API](https://youtu.be/0H99wUs0xTM?si=6c__04jrByFQtVpo)
 
 # Goal
 
-* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native)
-  .
+* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS, Native and
+  Wasm).
 * Provide basic multiplatform implementations for those abstractions (without significant performance optimization).
 * Provide bindings and wrappers with those abstractions for popular optimized platform libraries.
 
@@ -59,22 +63,24 @@ ${modules}
 KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the
 [common source sets](/kmath-core/src/commonMain) and implemented there wherever it is possible. In some cases, features
 are delegated to platform-specific implementations even if they could be provided in the common module for performance
-reasons. Currently, the Kotlin/JVM is the primary platform, however Kotlin/Native and Kotlin/JS contributions and
+reasons. Currently, Kotlin/JVM is the primary platform, however, Kotlin/Native and Kotlin/JS contributions and
 feedback are also welcome.
 
 ## Performance
 
-Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve both
+Calculation of performance is one of the major goals of KMath in the future, but in some cases it is impossible to
+achieve both
 performance and flexibility.
 
-We expect to focus on creating convenient universal API first and then work on increasing performance for specific
+We expect to focus on creating a convenient universal API first and then work on increasing performance for specific
 cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized
-native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be better than SciPy.
+native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be
+better than SciPy.
 
 ## Requirements
 
-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.
+KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend using GraalVM-CE or
+Oracle GraalVM for execution to get better performance.
 
 ### Repositories
 
@@ -94,11 +100,10 @@ dependencies {
 }
 ```
 
-Gradle `6.0+` is required for multiplatform artifacts.
-
 ## Contributing
 
-The project requires a lot of additional work. The most important thing we need is a feedback about what features are
+The project requires a lot of additional work. The most important thing we need is feedback about what features are
 required the most. Feel free to create feature requests. We are also welcome to code contributions, especially in issues
-marked with
-[waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label.
\ No newline at end of file
+marked
+with [good first issue](hhttps://github.com/SciProgCentre/kmath/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
+label.
\ No newline at end of file
diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts
index 7f2abc852..b74d6edca 100644
--- a/examples/build.gradle.kts
+++ b/examples/build.gradle.kts
@@ -52,7 +52,7 @@ dependencies {
 
     implementation("org.slf4j:slf4j-simple:1.7.32")
     // plotting
-    implementation("space.kscience:plotlykt-server:0.5.0")
+    implementation("space.kscience:plotlykt-server:0.7.0")
 }
 
 kotlin {
@@ -67,8 +67,8 @@ kotlin {
 }
 
 tasks.withType<KotlinJvmCompile> {
-    kotlinOptions {
-        freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" + "-Xlambdas=indy"
+    compilerOptions {
+        freeCompilerArgs.addAll("-Xjvm-default=all", "-Xopt-in=kotlin.RequiresOptIn", "-Xlambdas=indy")
     }
 }
 
diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt
index e85bab8d8..d792a4ec6 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt
index cacb6683e..a8150eb83 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,13 +8,13 @@ package space.kscience.kmath.ast
 import space.kscience.kmath.asm.compileToExpression
 import space.kscience.kmath.expressions.MstExtendedField
 import space.kscience.kmath.expressions.Symbol.Companion.x
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.invoke
 
 fun main() {
     val expr = MstExtendedField {
         x * 2.0 + number(2.0) / x - number(16.0) + asinh(x) / sin(x)
-    }.compileToExpression(DoubleField)
+    }.compileToExpression(Float64Field)
 
     val m = DoubleArray(expr.indexer.symbols.size)
     val xIdx = expr.indexer.indexOf(x)
diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt
index b443e639d..fc6cbb752 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt
@@ -1,16 +1,16 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.ast
 
+import space.kscience.kmath.expressions.Symbol.Companion.x
 import space.kscience.kmath.expressions.derivative
 import space.kscience.kmath.expressions.invoke
-import space.kscience.kmath.expressions.Symbol.Companion.x
 import space.kscience.kmath.expressions.toExpression
 import space.kscience.kmath.kotlingrad.toKotlingradExpression
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 
 /**
  * In this example, *x<sup>2</sup> &minus; 4 x &minus; 44* function is differentiated with Kotlin∇, and the
@@ -19,9 +19,9 @@ import space.kscience.kmath.operations.DoubleField
 fun main() {
     val actualDerivative = "x^2-4*x-44"
         .parseMath()
-        .toKotlingradExpression(DoubleField)
+        .toKotlingradExpression(Float64Field)
         .derivative(x)
 
-    val expectedDerivative = "2*x-4".parseMath().toExpression(DoubleField)
+    val expectedDerivative = "2*x-4".parseMath().toExpression(Float64Field)
     check(actualDerivative(x to 123.0) == expectedDerivative(x to 123.0))
 }
diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt
index 92ee1781b..549b96cf1 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -9,7 +9,7 @@ import space.kscience.kmath.expressions.Symbol.Companion.x
 import space.kscience.kmath.expressions.derivative
 import space.kscience.kmath.expressions.invoke
 import space.kscience.kmath.expressions.toExpression
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.symja.toSymjaExpression
 
 /**
@@ -19,9 +19,9 @@ import space.kscience.kmath.symja.toSymjaExpression
 fun main() {
     val actualDerivative = "x^2-4*x-44"
         .parseMath()
-        .toSymjaExpression(DoubleField)
+        .toSymjaExpression(Float64Field)
         .derivative(x)
 
-    val expectedDerivative = "2*x-4".parseMath().toExpression(DoubleField)
+    val expectedDerivative = "2*x-4".parseMath().toExpression(Float64Field)
     check(actualDerivative(x to 123.0) == expectedDerivative(x to 123.0))
 }
diff --git a/examples/src/main/kotlin/space/kscience/kmath/expressions/autodiff.kt b/examples/src/main/kotlin/space/kscience/kmath/expressions/autodiff.kt
index 863d6be7a..b9d7d4aa8 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/expressions/autodiff.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/expressions/autodiff.kt
@@ -1,11 +1,12 @@
 /*
- * Copyright 2018-2023 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.expressions
 
 import space.kscience.kmath.UnstableKMathAPI
+
 // Only kmath-core is needed.
 
 // Let's declare some variables
@@ -51,7 +52,7 @@ fun main() {
     // >>> 0.0
 
     // But in case you forgot to specify bound symbol's value, exception is thrown:
-    println( runCatching { someExpression(z to 4.0) } )
+    println(runCatching { someExpression(z to 4.0) })
     // >>> Failure(java.lang.IllegalStateException: Symbol 'x' is not supported in ...)
 
     // The reason is that the expression is evaluated lazily,
diff --git a/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt b/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt
index 258ed0c84..5c00e2d81 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -13,10 +13,7 @@ import space.kscience.kmath.expressions.autodiff
 import space.kscience.kmath.expressions.symbol
 import space.kscience.kmath.operations.asIterable
 import space.kscience.kmath.operations.toList
-import space.kscience.kmath.optimization.FunctionOptimizationTarget
-import space.kscience.kmath.optimization.optimizeWith
-import space.kscience.kmath.optimization.resultPoint
-import space.kscience.kmath.optimization.resultValue
+import space.kscience.kmath.optimization.*
 import space.kscience.kmath.random.RandomGenerator
 import space.kscience.kmath.real.DoubleVector
 import space.kscience.kmath.real.map
@@ -80,8 +77,9 @@ suspend fun main() {
     val result = chi2.optimizeWith(
         CMOptimizer,
         mapOf(a to 1.5, b to 0.9, c to 1.0),
-        FunctionOptimizationTarget.MINIMIZE
-    )
+    ) {
+        FunctionOptimizationTarget(OptimizationDirection.MINIMIZE)
+    }
 
     //display a page with plot and numerical results
     val page = Plotly.page {
@@ -98,7 +96,7 @@ suspend fun main() {
             scatter {
                 mode = ScatterMode.lines
                 x(x)
-                y(x.map { result.resultPoint[a]!! * it.pow(2) + result.resultPoint[b]!! * it + 1 })
+                y(x.map { result.result[a]!! * it.pow(2) + result.result[b]!! * it + 1 })
                 name = "fit"
             }
         }
diff --git a/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt b/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt
index fe7f48b72..4f3ce5443 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,6 +7,7 @@ package space.kscience.kmath.fit
 
 import kotlinx.html.br
 import kotlinx.html.h3
+import space.kscience.attributes.Attributes
 import space.kscience.kmath.data.XYErrorColumnarData
 import space.kscience.kmath.distributions.NormalDistribution
 import space.kscience.kmath.expressions.Symbol
@@ -64,7 +65,7 @@ suspend fun main() {
         QowOptimizer,
         Double.autodiff,
         mapOf(a to 0.9, b to 1.2, c to 2.0, e to 1.0, d to 1.0, e to 0.0),
-        OptimizationParameters(a, b, c, d)
+        attributes = Attributes(OptimizationParameters, listOf(a, b, c, d))
     ) { arg ->
         //bind variables to autodiff context
         val a by binding
@@ -94,13 +95,13 @@ suspend fun main() {
             scatter {
                 mode = ScatterMode.lines
                 x(x)
-                y(x.map { result.model(result.startPoint + result.resultPoint + (Symbol.x to it)) })
+                y(x.map { result.model(result.startPoint + result.result + (Symbol.x to it)) })
                 name = "fit"
             }
         }
         br()
         h3 {
-            +"Fit result: ${result.resultPoint}"
+            +"Fit result: ${result.result}"
         }
         h3 {
             +"Chi2/dof = ${result.chiSquaredOrNull!! / result.dof}"
diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt
index e8534d002..07bacc45d 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -13,7 +13,7 @@ import space.kscience.kmath.complex.algebra
 import space.kscience.kmath.integration.gaussIntegrator
 import space.kscience.kmath.integration.integrate
 import space.kscience.kmath.integration.value
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import kotlin.math.pow
 
 fun main() {
@@ -21,7 +21,7 @@ fun main() {
     val function: Function1D<Double> = { x -> 3 * x.pow(2) + 2 * x + 1 }
 
     //get the result of the integration
-    val result = DoubleField.gaussIntegrator.integrate(0.0..10.0, function = function)
+    val result = Float64Field.gaussIntegrator.integrate(0.0..10.0, function = function)
 
     //the value is nullable because in some cases the integration could not succeed
     println(result.value)
diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt
index b4ce6ad2d..c2e33afd4 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,8 +7,7 @@ package space.kscience.kmath.functions
 
 import space.kscience.kmath.interpolation.SplineInterpolator
 import space.kscience.kmath.interpolation.interpolatePolynomials
-import space.kscience.kmath.operations.DoubleField
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.plotly.Plotly
 import space.kscience.plotly.UnstablePlotlyAPI
 import space.kscience.plotly.makeFile
@@ -24,11 +23,9 @@ fun main() {
         x to sin(x)
     }
 
-    val polynomial: PiecewisePolynomial<Double> = SplineInterpolator(
-        DoubleField, ::DoubleBuffer
-    ).interpolatePolynomials(data)
+    val polynomial: PiecewisePolynomial<Double> = SplineInterpolator(Float64Field).interpolatePolynomials(data)
 
-    val function = polynomial.asFunction(DoubleField, 0.0)
+    val function = polynomial.asFunction(Float64Field, 0.0)
 
     val cmInterpolate = org.apache.commons.math3.analysis.interpolation.SplineInterpolator().interpolate(
         data.map { it.first }.toDoubleArray(),
diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt
index 7bcd96990..29a40498b 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,7 +7,7 @@ package space.kscience.kmath.functions
 
 import space.kscience.kmath.interpolation.interpolatePolynomials
 import space.kscience.kmath.interpolation.splineInterpolator
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.real.map
 import space.kscience.kmath.real.step
 import space.kscience.plotly.Plotly
@@ -28,9 +28,9 @@ fun main() {
     val xs = 0.0..100.0 step 0.5
     val ys = xs.map(function)
 
-    val polynomial: PiecewisePolynomial<Double> = DoubleField.splineInterpolator.interpolatePolynomials(xs, ys)
+    val polynomial: PiecewisePolynomial<Double> = Float64Field.splineInterpolator.interpolatePolynomials(xs, ys)
 
-    val polyFunction = polynomial.asFunction(DoubleField, 0.0)
+    val polyFunction = polynomial.asFunction(Float64Field, 0.0)
 
     Plotly.plot {
         scatter {
diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt
index baba2eb28..0680f42b0 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt
index 52451e9f3..b4afa37e4 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt b/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt
index 79eddc6c3..c59ffeae2 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt
@@ -1,33 +1,28 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.linear
 
-import space.kscience.kmath.operations.algebra
 import kotlin.random.Random
-import kotlin.time.ExperimentalTime
 import kotlin.time.measureTime
 
-@OptIn(ExperimentalTime::class)
-fun main() {
+fun main() = with(Float64ParallelLinearSpace) {
     val random = Random(12224)
     val dim = 1000
 
     //creating invertible matrix
-    val matrix1 = Double.algebra.linearSpace.buildMatrix(dim, dim) { i, j ->
+    val matrix1 = buildMatrix(dim, dim) { i, j ->
         if (i <= j) random.nextDouble() else 0.0
     }
-    val matrix2 = Double.algebra.linearSpace.buildMatrix(dim, dim) { i, j ->
+    val matrix2 = buildMatrix(dim, dim) { i, j ->
         if (i <= j) random.nextDouble() else 0.0
     }
 
     val time = measureTime {
-        with(Double.algebra.linearSpace) {
-            repeat(10) {
-                matrix1 dot matrix2
-            }
+        repeat(30) {
+            matrix1 dot matrix2
         }
     }
 
diff --git a/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt b/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt
index 52ed8f05f..6ebd1d221 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt
@@ -1,12 +1,12 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.linear
 
 import space.kscience.kmath.real.*
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 
 fun main() {
     val x0 = DoubleVector(0.0, 0.0, 0.0)
@@ -19,9 +19,9 @@ fun main() {
 
     fun ((Point<Double>) -> Double).grad(x: Point<Double>): Point<Double> {
         require(x.size == x0.size)
-        return DoubleBuffer(x.size) { i ->
+        return Float64Buffer(x.size) { i ->
             val h = sigma[i] / 5
-            val dVector = DoubleBuffer(x.size) { if (it == i) h else 0.0 }
+            val dVector = Float64Buffer(x.size) { if (it == i) h else 0.0 }
             val f1 = this(x + dVector / 2)
             val f0 = this(x - dVector / 2)
             (f1 - f0) / h
diff --git a/examples/src/main/kotlin/space/kscience/kmath/linear/lupPerformance.kt b/examples/src/main/kotlin/space/kscience/kmath/linear/lupPerformance.kt
new file mode 100644
index 000000000..dcd380ea6
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/linear/lupPerformance.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.linear
+
+import kotlin.random.Random
+import kotlin.time.measureTime
+
+fun main(): Unit = with(Float64LinearSpace) {
+    val random = Random(1224)
+    val dim = 500
+
+    //creating invertible matrix
+    val u = buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
+    val l = buildMatrix(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 }
+    val matrix = l dot u
+
+    val time = measureTime {
+        repeat(20) {
+            lupSolver().inverse(matrix)
+        }
+    }
+
+    println(time)
+}
\ No newline at end of file
diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt
index 2447d06ed..903388c2f 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt
index 77cfca4ae..a9c363dd6 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt
index 4a5d783e1..7af026759 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,21 +7,22 @@ package space.kscience.kmath.operations
 
 import space.kscience.kmath.commons.linear.CMLinearSpace
 import space.kscience.kmath.linear.matrix
-import space.kscience.kmath.nd.DoubleBufferND
-import space.kscience.kmath.nd.ShapeND
+import space.kscience.kmath.nd.Float64BufferND
 import space.kscience.kmath.nd.Structure2D
+import space.kscience.kmath.nd.mutableStructureND
 import space.kscience.kmath.nd.ndAlgebra
-import space.kscience.kmath.viktor.ViktorStructureND
 import space.kscience.kmath.viktor.viktorAlgebra
+import kotlin.collections.component1
+import kotlin.collections.component2
 
 fun main() {
-    val viktorStructure: ViktorStructureND = DoubleField.viktorAlgebra.structureND(ShapeND(2, 2)) { (i, j) ->
+    val viktorStructure = Float64Field.viktorAlgebra.mutableStructureND(2, 2) { (i, j) ->
         if (i == j) 2.0 else 0.0
     }
 
     val cmMatrix: Structure2D<Double> = CMLinearSpace.matrix(2, 2)(0.0, 1.0, 0.0, 3.0)
 
-    val res: DoubleBufferND = DoubleField.ndAlgebra {
+    val res: Float64BufferND = Float64Field.ndAlgebra {
         exp(viktorStructure) + 2.0 * cmMatrix
     }
 
diff --git a/examples/src/main/kotlin/space/kscience/kmath/series/DateTimeSeries.kt b/examples/src/main/kotlin/space/kscience/kmath/series/DateTimeSeries.kt
index ca10fc290..35435b64e 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/series/DateTimeSeries.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/series/DateTimeSeries.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2023 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/examples/src/main/kotlin/space/kscience/kmath/series/analyzeDif.kt b/examples/src/main/kotlin/space/kscience/kmath/series/analyzeDif.kt
index 0e10f1a9a..e6d3ef56b 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/series/analyzeDif.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/series/analyzeDif.kt
@@ -1,3 +1,8 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
 package space.kscience.kmath.series
 
 
@@ -13,7 +18,10 @@ import space.kscience.kmath.structures.slice
 import space.kscience.plotly.*
 import kotlin.math.PI
 
-fun main() = with(Double.algebra.bufferAlgebra.seriesAlgebra()) {
+fun Double.Companion.seriesAlgebra() = Double.algebra.bufferAlgebra.seriesAlgebra()
+
+
+fun main() = with(Double.seriesAlgebra()) {
 
 
     fun Plot.plotSeries(name: String, buffer: Buffer<Double>) {
@@ -36,10 +44,10 @@ fun main() = with(Double.algebra.bufferAlgebra.seriesAlgebra()) {
 
     Plotly.page {
         h1 { +"This is my plot" }
-        p{
+        p {
             +"Kolmogorov-smirnov test for s1 and s2: ${kmTest.value}"
         }
-        plot{
+        plot {
             plotSeries("s1", s1)
             plotSeries("s2", s2)
             plotSeries("s3", s3)
diff --git a/examples/src/main/kotlin/space/kscience/kmath/series/seriesBuilder.kt b/examples/src/main/kotlin/space/kscience/kmath/series/seriesBuilder.kt
new file mode 100644
index 000000000..9dfb0fdc9
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/series/seriesBuilder.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018-2023 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.series
+
+
+import space.kscience.kmath.structures.Buffer
+import space.kscience.kmath.structures.Float64Buffer
+import space.kscience.kmath.structures.asBuffer
+import space.kscience.kmath.structures.toDoubleArray
+import space.kscience.plotly.*
+import space.kscience.plotly.models.Scatter
+import space.kscience.plotly.models.ScatterMode
+import kotlin.random.Random
+
+fun main(): Unit = with(Double.seriesAlgebra()) {
+
+    val random = Random(1234)
+
+    val arrayOfRandoms = DoubleArray(20) { random.nextDouble() }
+
+    val series1: Float64Buffer = arrayOfRandoms.asBuffer()
+    val series2: Series<Double> = series1.moveBy(3)
+
+    val res = series2 - series1
+
+    println(res.size)
+
+    println(res)
+
+    fun Plot.series(name: String, buffer: Buffer<Double>, block: Scatter.() -> Unit = {}) {
+        scatter {
+            this.name = name
+            x.numbers = buffer.offsetIndices
+            y.doubles = buffer.toDoubleArray()
+            block()
+        }
+    }
+
+    Plotly.plot {
+        series("series1", series1)
+        series("series2", series2)
+        series("dif", res) {
+            mode = ScatterMode.lines
+            line.color("magenta")
+        }
+    }.makeFile(resourceLocation = ResourceLocation.REMOTE)
+}
\ No newline at end of file
diff --git a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt
index 031955e15..19b763113 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt
index 8e6d096ed..2f8e9d959 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt
index 86d7c0d89..9b48e44a0 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,12 +8,12 @@
 package space.kscience.kmath.structures
 
 import space.kscience.kmath.complex.*
-import space.kscience.kmath.linear.transpose
+import space.kscience.kmath.linear.transposed
 import space.kscience.kmath.nd.StructureND
 import space.kscience.kmath.nd.as2D
 import space.kscience.kmath.nd.ndAlgebra
 import space.kscience.kmath.nd.structureND
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.invoke
 import kotlin.system.measureTimeMillis
 
@@ -21,7 +21,7 @@ fun main() {
     val dim = 1000
     val n = 1000
 
-    val realField = DoubleField.ndAlgebra(dim, dim)
+    val realField = Float64Field.ndAlgebra(dim, dim)
     val complexField: ComplexFieldND = ComplexField.ndAlgebra(dim, dim)
 
     val realTime = measureTimeMillis {
@@ -60,7 +60,7 @@ fun complexExample() {
             val sum = matrix + x + 1.0
 
             //Represent the sum as 2d-structure and transpose
-            sum.as2D().transpose()
+            sum.as2D().transposed()
         }
     }
 }
diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt
index ba8f047a8..9ec8719ad 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -10,7 +10,7 @@ import kotlinx.coroutines.GlobalScope
 import org.nd4j.linalg.factory.Nd4j
 import space.kscience.kmath.nd.*
 import space.kscience.kmath.nd4j.nd4j
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.invoke
 import space.kscience.kmath.viktor.ViktorFieldND
 import kotlin.contracts.InvocationKind
@@ -33,15 +33,15 @@ fun main() {
 
 
     // specialized nd-field for Double. It works as generic Double field as well.
-    val doubleField = DoubleField.ndAlgebra
+    val doubleField = Float64Field.ndAlgebra
     //A generic field. It should be used for objects, not primitives.
-    val genericField = BufferedFieldOpsND(DoubleField)
+    val genericField = BufferedFieldOpsND(Float64Field)
     // Nd4j specialized field.
-    val nd4jField = DoubleField.nd4j
+    val nd4jField = Float64Field.nd4j
     //viktor field
     val viktorField = ViktorFieldND(dim, dim)
     //parallel processing based on Java Streams
-    val parallelField = DoubleField.ndStreaming(dim, dim)
+    val parallelField = Float64Field.ndStreaming(dim, dim)
 
     measureAndPrint("Boxing addition") {
         genericField {
diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt
index 2ce2c21a6..3a59423d4 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -9,6 +9,7 @@ import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.nd.*
 import space.kscience.kmath.operations.DoubleField
 import space.kscience.kmath.operations.ExtendedField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.NumbersAddOps
 import java.util.*
 import java.util.stream.IntStream
@@ -17,12 +18,12 @@ import java.util.stream.IntStream
  * A demonstration implementation of NDField over Real using Java [java.util.stream.DoubleStream] for parallel
  * execution.
  */
-class StreamDoubleFieldND(override val shape: ShapeND) : FieldND<Double, DoubleField>,
+class StreamDoubleFieldND(override val shape: ShapeND) : FieldND<Double, Float64Field>,
     NumbersAddOps<StructureND<Double>>,
     ExtendedField<StructureND<Double>> {
 
     private val strides = ColumnStrides(shape)
-    override val elementAlgebra: DoubleField get() = DoubleField
+    override val elementAlgebra: Float64Field get() = Float64Field
     override val zero: BufferND<Double> by lazy { structureND(shape) { zero } }
     override val one: BufferND<Double> by lazy { structureND(shape) { one } }
 
@@ -32,40 +33,52 @@ class StreamDoubleFieldND(override val shape: ShapeND) : FieldND<Double, DoubleF
     }
 
     @OptIn(PerformancePitfall::class)
-    private val StructureND<Double>.buffer: DoubleBuffer
+    private val StructureND<Double>.buffer: Float64Buffer
         get() = when {
             !shape.contentEquals(this@StreamDoubleFieldND.shape) -> throw ShapeMismatchException(
                 this@StreamDoubleFieldND.shape,
                 shape
             )
 
-            this is BufferND && indices == this@StreamDoubleFieldND.strides -> this.buffer as DoubleBuffer
-            else -> DoubleBuffer(strides.linearSize) { offset -> get(strides.index(offset)) }
+            this is BufferND && indices == this@StreamDoubleFieldND.strides -> this.buffer as Float64Buffer
+            else -> Float64Buffer(strides.linearSize) { offset -> get(strides.index(offset)) }
         }
 
-    override fun structureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): BufferND<Double> {
+    override fun structureND(shape: ShapeND, initializer: Float64Field.(IntArray) -> Double): BufferND<Double> {
         val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
             val index = strides.index(offset)
-            DoubleField.initializer(index)
+            Float64Field.initializer(index)
         }.toArray()
 
         return BufferND(strides, array.asBuffer())
     }
 
+    override fun mutableStructureND(
+        shape: ShapeND,
+        initializer: DoubleField.(IntArray) -> Double,
+    ): MutableBufferND<Double> {
+        val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
+            val index = strides.index(offset)
+            DoubleField.initializer(index)
+        }.toArray()
+
+        return MutableBufferND(strides, array.asBuffer())
+    }
+
     @OptIn(PerformancePitfall::class)
     override fun StructureND<Double>.map(
-        transform: DoubleField.(Double) -> Double,
+        transform: Float64Field.(Double) -> Double,
     ): BufferND<Double> {
-        val array = Arrays.stream(buffer.array).parallel().map { DoubleField.transform(it) }.toArray()
+        val array = Arrays.stream(buffer.array).parallel().map { Float64Field.transform(it) }.toArray()
         return BufferND(strides, array.asBuffer())
     }
 
     @OptIn(PerformancePitfall::class)
     override fun StructureND<Double>.mapIndexed(
-        transform: DoubleField.(index: IntArray, Double) -> Double,
+        transform: Float64Field.(index: IntArray, Double) -> Double,
     ): BufferND<Double> {
         val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
-            DoubleField.transform(
+            Float64Field.transform(
                 strides.index(offset),
                 buffer.array[offset]
             )
@@ -78,10 +91,10 @@ class StreamDoubleFieldND(override val shape: ShapeND) : FieldND<Double, DoubleF
     override fun zip(
         left: StructureND<Double>,
         right: StructureND<Double>,
-        transform: DoubleField.(Double, Double) -> Double,
+        transform: Float64Field.(Double, Double) -> Double,
     ): BufferND<Double> {
         val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
-            DoubleField.transform(left.buffer.array[offset], right.buffer.array[offset])
+            Float64Field.transform(left.buffer.array[offset], right.buffer.array[offset])
         }.toArray()
         return BufferND(strides, array.asBuffer())
     }
@@ -111,4 +124,4 @@ class StreamDoubleFieldND(override val shape: ShapeND) : FieldND<Double, DoubleF
     override fun atanh(arg: StructureND<Double>): BufferND<Double> = arg.map { atanh(it) }
 }
 
-fun DoubleField.ndStreaming(vararg shape: Int): StreamDoubleFieldND = StreamDoubleFieldND(ShapeND(shape))
+fun Float64Field.ndStreaming(vararg shape: Int): StreamDoubleFieldND = StreamDoubleFieldND(ShapeND(shape))
diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt
index e6ff0ee28..4d52c4258 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -16,7 +16,7 @@ import kotlin.system.measureTimeMillis
 fun main() {
     val n = 6000
     val array = DoubleArray(n * n) { 1.0 }
-    val buffer = DoubleBuffer(array)
+    val buffer = Float64Buffer(array)
     val strides = ColumnStrides(ShapeND(n, n))
     val structure = BufferND(strides, buffer)
 
diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt
index 14c058417..8d642d892 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt
@@ -1,25 +1,23 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.structures
 
 import space.kscience.kmath.nd.BufferND
-import space.kscience.kmath.nd.ShapeND
-import space.kscience.kmath.nd.StructureND
 import space.kscience.kmath.operations.mapToBuffer
 import kotlin.system.measureTimeMillis
 
 private inline fun <T, reified R : Any> BufferND<T>.mapToBufferND(
-    bufferFactory: BufferFactory<R> = BufferFactory.auto(),
+    bufferFactory: BufferFactory<R> = BufferFactory(),
     crossinline block: (T) -> R,
 ): BufferND<R> = BufferND(indices, buffer.mapToBuffer(bufferFactory, block))
 
 @Suppress("UNUSED_VARIABLE")
 fun main() {
     val n = 6000
-    val structure = StructureND.buffered(ShapeND(n, n), Buffer.Companion::auto) { 1.0 }
+    val structure = BufferND(n, n) { 1.0 }
     structure.mapToBufferND { it + 1 } // warm-up
     val time1 = measureTimeMillis { val res = structure.mapToBufferND { it + 1 } }
     println("Structure mapping finished in $time1 millis")
@@ -32,10 +30,10 @@ fun main() {
 
     println("Array mapping finished in $time2 millis")
 
-    val buffer = DoubleBuffer(DoubleArray(n * n) { 1.0 })
+    val buffer = Float64Buffer(DoubleArray(n * n) { 1.0 })
 
     val time3 = measureTimeMillis {
-        val target = DoubleBuffer(DoubleArray(n * n))
+        val target = Float64Buffer(DoubleArray(n * n))
         val res = array.forEachIndexed { index, value ->
             target[index] = value + 1
         }
diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt
index 2ac0dc6a4..82d2f8eb3 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt
@@ -1,23 +1,23 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.structures
 
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.buffer
 import space.kscience.kmath.operations.bufferAlgebra
 import space.kscience.kmath.operations.withSize
 
 inline fun <reified R : Any> MutableBuffer.Companion.same(
     n: Int,
-    value: R
-): MutableBuffer<R> = auto(n) { value }
+    value: R,
+): MutableBuffer<R> = MutableBuffer(n) { value }
 
 
 fun main() {
-    with(DoubleField.bufferAlgebra.withSize(5)) {
+    with(Float64Field.bufferAlgebra.withSize(5)) {
         println(number(2.0) + buffer(1, 2, 3, 4, 5))
     }
 }
diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/mutableNd.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/mutableNd.kt
new file mode 100644
index 000000000..0b0a4cac1
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/structures/mutableNd.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2018-2023 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.structures
+
+import space.kscience.kmath.PerformancePitfall
+import space.kscience.kmath.nd.*
+import space.kscience.kmath.operations.algebra
+
+@OptIn(PerformancePitfall::class)
+fun main(): Unit = with(Double.algebra.ndAlgebra) {
+    val structure: MutableStructure2D<Double> = mutableStructureND(ShapeND(2, 2)) { (i, j) ->
+        i.toDouble() + j.toDouble()
+    }.as2D()
+
+    structure[0, 1] = -2.0
+
+    val structure2 = mutableStructureND(2, 2) { (i, j) -> i.toDouble() + j.toDouble() }.as2D()
+
+    structure2[0, 1] = 2.0
+
+
+    println(structure + structure2)
+}
\ No newline at end of file
diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt
index 1ba0e3503..a4dacb881 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -15,7 +15,7 @@ private fun DMatrixContext<Double, *>.simple() {
     val m2 = produce<D3, D2> { i, j -> (i + j).toDouble() }
 
     //Dimension-safe addition
-    m1.transpose() + m2
+    m1.transposed() + m2
 }
 
 private object D5 : Dimension {
diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/StaticLm/staticDifficultTest.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/StaticLm/staticDifficultTest.kt
new file mode 100644
index 000000000..490e5d6a4
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/StaticLm/staticDifficultTest.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.tensors.LevenbergMarquardt.StaticLm
+
+import space.kscience.kmath.nd.ShapeND
+import space.kscience.kmath.nd.as2D
+import space.kscience.kmath.nd.component1
+import space.kscience.kmath.tensors.LevenbergMarquardt.funcDifficultForLm
+import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra
+import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.div
+import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
+import space.kscience.kmath.tensors.core.LMInput
+import space.kscience.kmath.tensors.core.levenbergMarquardt
+import kotlin.math.roundToInt
+
+fun main() {
+    val NData = 200
+    var t_example = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(NData, 1))).as2D()
+    for (i in 0 until NData) {
+        t_example[i, 0] = t_example[i, 0] * (i + 1) - 104
+    }
+
+    val Nparams = 15
+    var p_example = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1))).as2D()
+    for (i in 0 until Nparams) {
+        p_example[i, 0] = p_example[i, 0] + i - 25
+    }
+
+    val exampleNumber = 1
+
+    var y_hat = funcDifficultForLm(t_example, p_example, exampleNumber)
+
+    var p_init = DoubleTensorAlgebra.zeros(ShapeND(intArrayOf(Nparams, 1))).as2D()
+    for (i in 0 until Nparams) {
+        p_init[i, 0] = (p_example[i, 0] + 0.9)
+    }
+
+    var t = t_example
+    val y_dat = y_hat
+    val weight = 1.0 / Nparams * 1.0 - 0.085
+    val dp = BroadcastDoubleTensorAlgebra.fromArray(
+        ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }
+    ).as2D()
+    var p_min = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1)))
+    p_min = p_min.div(1.0 / -50.0)
+    val p_max = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1)))
+    p_min = p_min.div(1.0 / 50.0)
+    val opts = doubleArrayOf(3.0, 10000.0, 1e-6, 1e-6, 1e-6, 1e-6, 1e-2, 11.0, 9.0, 1.0)
+//    val opts = doubleArrayOf(3.0, 10000.0, 1e-6, 1e-6, 1e-6, 1e-6, 1e-3, 11.0, 9.0, 1.0)
+
+    val inputData = LMInput(
+        ::funcDifficultForLm,
+        p_init.as2D(),
+        t,
+        y_dat,
+        weight,
+        dp,
+        p_min.as2D(),
+        p_max.as2D(),
+        opts[1].toInt(),
+        doubleArrayOf(opts[2], opts[3], opts[4], opts[5]),
+        doubleArrayOf(opts[6], opts[7], opts[8]),
+        opts[9].toInt(),
+        10,
+        1
+    )
+
+    val result = DoubleTensorAlgebra.levenbergMarquardt(inputData)
+
+    println("Parameters:")
+    for (i in 0 until result.resultParameters.shape.component1()) {
+        val x = (result.resultParameters[i, 0] * 10000).roundToInt() / 10000.0
+        print("$x ")
+    }
+    println()
+
+    println("Y true and y received:")
+    var y_hat_after = funcDifficultForLm(t_example, result.resultParameters, exampleNumber)
+    for (i in 0 until y_hat.shape.component1()) {
+        val x = (y_hat[i, 0] * 10000).roundToInt() / 10000.0
+        val y = (y_hat_after[i, 0] * 10000).roundToInt() / 10000.0
+        println("$x $y")
+    }
+
+    println("Сhi_sq:")
+    println(result.resultChiSq)
+    println("Number of iterations:")
+    println(result.iterations)
+}
\ No newline at end of file
diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/StaticLm/staticEasyTest.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/StaticLm/staticEasyTest.kt
new file mode 100644
index 000000000..1b5abbd36
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/StaticLm/staticEasyTest.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.tensors.LevenbergMarquardt.StaticLm
+
+import space.kscience.kmath.nd.ShapeND
+import space.kscience.kmath.nd.as2D
+import space.kscience.kmath.nd.component1
+import space.kscience.kmath.tensors.LevenbergMarquardt.funcDifficultForLm
+import space.kscience.kmath.tensors.LevenbergMarquardt.funcEasyForLm
+import space.kscience.kmath.tensors.LevenbergMarquardt.getStartDataForFuncEasy
+import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
+import space.kscience.kmath.tensors.core.LMInput
+import space.kscience.kmath.tensors.core.levenbergMarquardt
+import kotlin.math.roundToInt
+
+fun main() {
+    val startedData = getStartDataForFuncEasy()
+    val inputData = LMInput(
+        ::funcEasyForLm,
+        DoubleTensorAlgebra.ones(ShapeND(intArrayOf(4, 1))).as2D(),
+        startedData.t,
+        startedData.y_dat,
+        startedData.weight,
+        startedData.dp,
+        startedData.p_min,
+        startedData.p_max,
+        startedData.opts[1].toInt(),
+        doubleArrayOf(startedData.opts[2], startedData.opts[3], startedData.opts[4], startedData.opts[5]),
+        doubleArrayOf(startedData.opts[6], startedData.opts[7], startedData.opts[8]),
+        startedData.opts[9].toInt(),
+        10,
+        startedData.example_number
+    )
+
+    val result = DoubleTensorAlgebra.levenbergMarquardt(inputData)
+
+    println("Parameters:")
+    for (i in 0 until result.resultParameters.shape.component1()) {
+        val x = (result.resultParameters[i, 0] * 10000).roundToInt() / 10000.0
+        print("$x ")
+    }
+    println()
+
+    println("Y true and y received:")
+    var y_hat_after = funcDifficultForLm(startedData.t, result.resultParameters, startedData.example_number)
+    for (i in 0 until startedData.y_dat.shape.component1()) {
+        val x = (startedData.y_dat[i, 0] * 10000).roundToInt() / 10000.0
+        val y = (y_hat_after[i, 0] * 10000).roundToInt() / 10000.0
+        println("$x $y")
+    }
+
+    println("Сhi_sq:")
+    println(result.resultChiSq)
+    println("Number of iterations:")
+    println(result.iterations)
+}
\ No newline at end of file
diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/StaticLm/staticMiddleTest.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/StaticLm/staticMiddleTest.kt
new file mode 100644
index 000000000..ac26debb9
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/StaticLm/staticMiddleTest.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.tensors.LevenbergMarquardt.StaticLm
+
+import space.kscience.kmath.nd.ShapeND
+import space.kscience.kmath.nd.as2D
+import space.kscience.kmath.nd.component1
+import space.kscience.kmath.tensors.LevenbergMarquardt.funcMiddleForLm
+import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra
+import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.div
+import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
+import space.kscience.kmath.tensors.core.LMInput
+import space.kscience.kmath.tensors.core.levenbergMarquardt
+import kotlin.math.roundToInt
+
+fun main() {
+    val NData = 100
+    var t_example = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(NData, 1))).as2D()
+    for (i in 0 until NData) {
+        t_example[i, 0] = t_example[i, 0] * (i + 1)
+    }
+
+    val Nparams = 20
+    var p_example = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1))).as2D()
+    for (i in 0 until Nparams) {
+        p_example[i, 0] = p_example[i, 0] + i - 25
+    }
+
+    val exampleNumber = 1
+
+    var y_hat = funcMiddleForLm(t_example, p_example, exampleNumber)
+
+    var p_init = DoubleTensorAlgebra.zeros(ShapeND(intArrayOf(Nparams, 1))).as2D()
+    for (i in 0 until Nparams) {
+        p_init[i, 0] = (p_example[i, 0] + 0.9)
+    }
+
+    var t = t_example
+    val y_dat = y_hat
+    val weight = 1.0
+    val dp = BroadcastDoubleTensorAlgebra.fromArray(
+        ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }
+    ).as2D()
+    var p_min = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1)))
+    p_min = p_min.div(1.0 / -50.0)
+    val p_max = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1)))
+    p_min = p_min.div(1.0 / 50.0)
+    val opts = doubleArrayOf(3.0, 7000.0, 1e-5, 1e-5, 1e-5, 1e-5, 1e-5, 11.0, 9.0, 1.0)
+
+    val inputData = LMInput(
+        ::funcMiddleForLm,
+        p_init.as2D(),
+        t,
+        y_dat,
+        weight,
+        dp,
+        p_min.as2D(),
+        p_max.as2D(),
+        opts[1].toInt(),
+        doubleArrayOf(opts[2], opts[3], opts[4], opts[5]),
+        doubleArrayOf(opts[6], opts[7], opts[8]),
+        opts[9].toInt(),
+        10,
+        1
+    )
+
+    val result = DoubleTensorAlgebra.levenbergMarquardt(inputData)
+
+    println("Parameters:")
+    for (i in 0 until result.resultParameters.shape.component1()) {
+        val x = (result.resultParameters[i, 0] * 10000).roundToInt() / 10000.0
+        print("$x ")
+    }
+    println()
+
+
+    var y_hat_after = funcMiddleForLm(t_example, result.resultParameters, exampleNumber)
+    for (i in 0 until y_hat.shape.component1()) {
+        val x = (y_hat[i, 0] * 10000).roundToInt() / 10000.0
+        val y = (y_hat_after[i, 0] * 10000).roundToInt() / 10000.0
+        println("$x $y")
+    }
+
+    println("Сhi_sq:")
+    println(result.resultChiSq)
+    println("Number of iterations:")
+    println(result.iterations)
+}
\ No newline at end of file
diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/StreamingLm/streamLm.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/StreamingLm/streamLm.kt
new file mode 100644
index 000000000..dca7325ce
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/StreamingLm/streamLm.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.tensors.LevenbergMarquardt.StreamingLm
+
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flow
+import space.kscience.kmath.nd.MutableStructure2D
+import space.kscience.kmath.nd.ShapeND
+import space.kscience.kmath.nd.as2D
+import space.kscience.kmath.nd.component1
+import space.kscience.kmath.tensors.LevenbergMarquardt.StartDataLm
+import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.zeros
+import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
+import space.kscience.kmath.tensors.core.LMInput
+import space.kscience.kmath.tensors.core.levenbergMarquardt
+import kotlin.random.Random
+
+fun streamLm(
+    lm_func: (MutableStructure2D<Double>, MutableStructure2D<Double>, Int) -> (MutableStructure2D<Double>),
+    startData: StartDataLm, launchFrequencyInMs: Long, numberOfLaunches: Int,
+): Flow<MutableStructure2D<Double>> = flow {
+
+    var example_number = startData.example_number
+    var p_init = startData.p_init
+    var t = startData.t
+    var y_dat = startData.y_dat
+    val weight = startData.weight
+    val dp = startData.dp
+    val p_min = startData.p_min
+    val p_max = startData.p_max
+    val opts = startData.opts
+
+    var steps = numberOfLaunches
+    val isEndless = (steps <= 0)
+
+    val inputData = LMInput(
+        lm_func,
+        p_init,
+        t,
+        y_dat,
+        weight,
+        dp,
+        p_min,
+        p_max,
+        opts[1].toInt(),
+        doubleArrayOf(opts[2], opts[3], opts[4], opts[5]),
+        doubleArrayOf(opts[6], opts[7], opts[8]),
+        opts[9].toInt(),
+        10,
+        example_number
+    )
+
+    while (isEndless || steps > 0) {
+        val result = DoubleTensorAlgebra.levenbergMarquardt(inputData)
+        emit(result.resultParameters)
+        delay(launchFrequencyInMs)
+        inputData.realValues = generateNewYDat(y_dat, 0.1)
+        inputData.startParameters = result.resultParameters
+        if (!isEndless) steps -= 1
+    }
+}
+
+fun generateNewYDat(y_dat: MutableStructure2D<Double>, delta: Double): MutableStructure2D<Double> {
+    val n = y_dat.shape.component1()
+    val y_dat_new = zeros(ShapeND(intArrayOf(n, 1))).as2D()
+    for (i in 0 until n) {
+        val randomEps = Random.nextDouble(delta + delta) - delta
+        y_dat_new[i, 0] = y_dat[i, 0] + randomEps
+    }
+    return y_dat_new
+}
\ No newline at end of file
diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/StreamingLm/streamingLmTest.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/StreamingLm/streamingLmTest.kt
new file mode 100644
index 000000000..cd9115e7b
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/StreamingLm/streamingLmTest.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.tensors.LevenbergMarquardt.StreamingLm
+
+import space.kscience.kmath.nd.component1
+import space.kscience.kmath.tensors.LevenbergMarquardt.funcDifficultForLm
+import space.kscience.kmath.tensors.LevenbergMarquardt.getStartDataForFuncDifficult
+import kotlin.math.roundToInt
+
+suspend fun main() {
+    val startData = getStartDataForFuncDifficult()
+    // Создание потока:
+    val lmFlow = streamLm(::funcDifficultForLm, startData, 0, 100)
+    var initialTime = System.currentTimeMillis()
+    var lastTime: Long
+    val launches = mutableListOf<Long>()
+    // Запуск потока
+    lmFlow.collect { parameters ->
+        lastTime = System.currentTimeMillis()
+        launches.add(lastTime - initialTime)
+        initialTime = lastTime
+        for (i in 0 until parameters.shape.component1()) {
+            val x = (parameters[i, 0] * 10000).roundToInt() / 10000.0
+            print("$x ")
+            if (i == parameters.shape.component1() - 1) println()
+        }
+    }
+
+    println("Average without first is: ${launches.subList(1, launches.size - 1).average()}")
+}
\ No newline at end of file
diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/functionsToOptimize.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/functionsToOptimize.kt
new file mode 100644
index 000000000..9a4b613b2
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LevenbergMarquardt/functionsToOptimize.kt
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.tensors.LevenbergMarquardt
+
+import space.kscience.kmath.nd.MutableStructure2D
+import space.kscience.kmath.nd.ShapeND
+import space.kscience.kmath.nd.as2D
+import space.kscience.kmath.nd.component1
+import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra
+import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.div
+import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
+import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.max
+import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.plus
+import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.pow
+import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.times
+import space.kscience.kmath.tensors.core.asDoubleTensor
+
+public data class StartDataLm(
+    var lm_matx_y_dat: MutableStructure2D<Double>,
+    var example_number: Int,
+    var p_init: MutableStructure2D<Double>,
+    var t: MutableStructure2D<Double>,
+    var y_dat: MutableStructure2D<Double>,
+    var weight: Double,
+    var dp: MutableStructure2D<Double>,
+    var p_min: MutableStructure2D<Double>,
+    var p_max: MutableStructure2D<Double>,
+    var consts: MutableStructure2D<Double>,
+    var opts: DoubleArray,
+)
+
+fun funcEasyForLm(
+    t: MutableStructure2D<Double>,
+    p: MutableStructure2D<Double>,
+    exampleNumber: Int,
+): MutableStructure2D<Double> {
+    val m = t.shape.component1()
+    var y_hat = DoubleTensorAlgebra.zeros(ShapeND(intArrayOf(m, 1)))
+
+    if (exampleNumber == 1) {
+        y_hat = DoubleTensorAlgebra.exp((t.times(-1.0 / p[1, 0]))).times(p[0, 0]) + t.times(p[2, 0]).times(
+            DoubleTensorAlgebra.exp((t.times(-1.0 / p[3, 0])))
+        )
+    } else if (exampleNumber == 2) {
+        val mt = t.max()
+        y_hat = (t.times(1.0 / mt)).times(p[0, 0]) +
+                (t.times(1.0 / mt)).pow(2).times(p[1, 0]) +
+                (t.times(1.0 / mt)).pow(3).times(p[2, 0]) +
+                (t.times(1.0 / mt)).pow(4).times(p[3, 0])
+    } else if (exampleNumber == 3) {
+        y_hat = DoubleTensorAlgebra.exp((t.times(-1.0 / p[1, 0])))
+            .times(p[0, 0]) + DoubleTensorAlgebra.sin((t.times(1.0 / p[3, 0]))).times(p[2, 0])
+    }
+
+    return y_hat.as2D()
+}
+
+fun funcMiddleForLm(
+    t: MutableStructure2D<Double>,
+    p: MutableStructure2D<Double>,
+    exampleNumber: Int,
+): MutableStructure2D<Double> {
+    val m = t.shape.component1()
+    var y_hat = DoubleTensorAlgebra.zeros(ShapeND(intArrayOf(m, 1)))
+
+    val mt = t.max()
+    for (i in 0 until p.shape.component1()) {
+        y_hat += (t.times(1.0 / mt)).times(p[i, 0])
+    }
+
+    for (i in 0 until 5) {
+        y_hat = funcEasyForLm(y_hat.as2D(), p, exampleNumber).asDoubleTensor()
+    }
+
+    return y_hat.as2D()
+}
+
+fun funcDifficultForLm(
+    t: MutableStructure2D<Double>,
+    p: MutableStructure2D<Double>,
+    exampleNumber: Int,
+): MutableStructure2D<Double> {
+    val m = t.shape.component1()
+    var y_hat = DoubleTensorAlgebra.zeros(ShapeND(intArrayOf(m, 1)))
+
+    val mt = t.max()
+    for (i in 0 until p.shape.component1()) {
+        y_hat = y_hat.plus((t.times(1.0 / mt)).times(p[i, 0]))
+    }
+
+    for (i in 0 until 4) {
+        y_hat = funcEasyForLm((y_hat.as2D() + t).as2D(), p, exampleNumber).asDoubleTensor()
+    }
+
+    return y_hat.as2D()
+}
+
+
+fun getStartDataForFuncDifficult(): StartDataLm {
+    val NData = 200
+    var t_example = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(NData, 1))).as2D()
+    for (i in 0 until NData) {
+        t_example[i, 0] = t_example[i, 0] * (i + 1) - 104
+    }
+
+    val Nparams = 15
+    var p_example = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1))).as2D()
+    for (i in 0 until Nparams) {
+        p_example[i, 0] = p_example[i, 0] + i - 25
+    }
+
+    val exampleNumber = 1
+
+    var y_hat = funcDifficultForLm(t_example, p_example, exampleNumber)
+
+    var p_init = DoubleTensorAlgebra.zeros(ShapeND(intArrayOf(Nparams, 1))).as2D()
+    for (i in 0 until Nparams) {
+        p_init[i, 0] = (p_example[i, 0] + 0.9)
+    }
+
+    var t = t_example
+    val y_dat = y_hat
+    val weight = 1.0 / Nparams * 1.0 - 0.085
+    val dp = BroadcastDoubleTensorAlgebra.fromArray(
+        ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }
+    ).as2D()
+    var p_min = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1)))
+    p_min = p_min.div(1.0 / -50.0)
+    val p_max = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1)))
+    p_min = p_min.div(1.0 / 50.0)
+    val consts = BroadcastDoubleTensorAlgebra.fromArray(
+        ShapeND(intArrayOf(1, 1)), doubleArrayOf(0.0)
+    ).as2D()
+    val opts = doubleArrayOf(3.0, 10000.0, 1e-2, 1e-3, 1e-2, 1e-2, 1e-2, 11.0, 9.0, 1.0)
+
+    return StartDataLm(y_dat, 1, p_init, t, y_dat, weight, dp, p_min.as2D(), p_max.as2D(), consts, opts)
+}
+
+fun getStartDataForFuncMiddle(): StartDataLm {
+    val NData = 100
+    var t_example = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(NData, 1))).as2D()
+    for (i in 0 until NData) {
+        t_example[i, 0] = t_example[i, 0] * (i + 1)
+    }
+
+    val Nparams = 20
+    var p_example = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1))).as2D()
+    for (i in 0 until Nparams) {
+        p_example[i, 0] = p_example[i, 0] + i - 25
+    }
+
+    val exampleNumber = 1
+
+    var y_hat = funcMiddleForLm(t_example, p_example, exampleNumber)
+
+    var p_init = DoubleTensorAlgebra.zeros(ShapeND(intArrayOf(Nparams, 1))).as2D()
+    for (i in 0 until Nparams) {
+        p_init[i, 0] = (p_example[i, 0] + 10.0)
+    }
+    var t = t_example
+    val y_dat = y_hat
+    val weight = 1.0
+    val dp = BroadcastDoubleTensorAlgebra.fromArray(
+        ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }
+    ).as2D()
+    var p_min = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1)))
+    p_min = p_min.div(1.0 / -50.0)
+    val p_max = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(Nparams, 1)))
+    p_min = p_min.div(1.0 / 50.0)
+    val consts = BroadcastDoubleTensorAlgebra.fromArray(
+        ShapeND(intArrayOf(1, 1)), doubleArrayOf(0.0)
+    ).as2D()
+    val opts = doubleArrayOf(3.0, 10000.0, 1e-5, 1e-5, 1e-5, 1e-5, 1e-5, 11.0, 9.0, 1.0)
+
+    var example_number = 1
+
+    return StartDataLm(y_dat, example_number, p_init, t, y_dat, weight, dp, p_min.as2D(), p_max.as2D(), consts, opts)
+}
+
+fun getStartDataForFuncEasy(): StartDataLm {
+    val lm_matx_y_dat = doubleArrayOf(
+        19.6594, 18.6096, 17.6792, 17.2747, 16.3065, 17.1458, 16.0467, 16.7023, 15.7809, 15.9807,
+        14.7620, 15.1128, 16.0973, 15.1934, 15.8636, 15.4763, 15.6860, 15.1895, 15.3495, 16.6054,
+        16.2247, 15.9854, 16.1421, 17.0960, 16.7769, 17.1997, 17.2767, 17.5882, 17.5378, 16.7894,
+        17.7648, 18.2512, 18.1581, 16.7037, 17.8475, 17.9081, 18.3067, 17.9632, 18.2817, 19.1427,
+        18.8130, 18.5658, 18.0056, 18.4607, 18.5918, 18.2544, 18.3731, 18.7511, 19.3181, 17.3066,
+        17.9632, 19.0513, 18.7528, 18.2928, 18.5967, 17.8567, 17.7859, 18.4016, 18.9423, 18.4959,
+        17.8000, 18.4251, 17.7829, 17.4645, 17.5221, 17.3517, 17.4637, 17.7563, 16.8471, 17.4558,
+        17.7447, 17.1487, 17.3183, 16.8312, 17.7551, 17.0942, 15.6093, 16.4163, 15.3755, 16.6725,
+        16.2332, 16.2316, 16.2236, 16.5361, 15.3721, 15.3347, 15.5815, 15.6319, 14.4538, 14.6044,
+        14.7665, 13.3718, 15.0587, 13.8320, 14.7873, 13.6824, 14.2579, 14.2154, 13.5818, 13.8157
+    )
+
+    var example_number = 1
+    val p_init = BroadcastDoubleTensorAlgebra.fromArray(
+        ShapeND(intArrayOf(4, 1)), doubleArrayOf(5.0, 2.0, 0.2, 10.0)
+    ).as2D()
+
+    var t = DoubleTensorAlgebra.ones(ShapeND(intArrayOf(100, 1))).as2D()
+    for (i in 0 until 100) {
+        t[i, 0] = t[i, 0] * (i + 1)
+    }
+
+    val y_dat = BroadcastDoubleTensorAlgebra.fromArray(
+        ShapeND(intArrayOf(100, 1)), lm_matx_y_dat
+    ).as2D()
+
+    val weight = 4.0
+
+    val dp = BroadcastDoubleTensorAlgebra.fromArray(
+        ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }
+    ).as2D()
+
+    val p_min = BroadcastDoubleTensorAlgebra.fromArray(
+        ShapeND(intArrayOf(4, 1)), doubleArrayOf(-50.0, -20.0, -2.0, -100.0)
+    ).as2D()
+
+    val p_max = BroadcastDoubleTensorAlgebra.fromArray(
+        ShapeND(intArrayOf(4, 1)), doubleArrayOf(50.0, 20.0, 2.0, 100.0)
+    ).as2D()
+
+    val consts = BroadcastDoubleTensorAlgebra.fromArray(
+        ShapeND(intArrayOf(1, 1)), doubleArrayOf(0.0)
+    ).as2D()
+
+    val opts = doubleArrayOf(3.0, 100.0, 1e-3, 1e-3, 1e-1, 1e-1, 1e-2, 11.0, 9.0, 1.0)
+
+    return StartDataLm(y_dat, example_number, p_init, t, y_dat, weight, dp, p_min, p_max, consts, opts)
+}
\ No newline at end of file
diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt
index 2c570ea34..8de4ab527 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt
index fb774a39d..10edcd03a 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/dataSetNormalization.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/dataSetNormalization.kt
index 45c2ff120..e804e5818 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/tensors/dataSetNormalization.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/dataSetNormalization.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt
index 238696cf9..d5b04e153 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt
index 67e0631e7..f8bf65ad7 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt
index 8fd5ae5ad..78f27c304 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/gradle.properties b/gradle.properties
index e33106c0c..319ce3df0 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -5,12 +5,10 @@
 kotlin.code.style=official
 kotlin.mpp.stability.nowarn=true
 kotlin.native.ignoreDisabledTargets=true
-
 org.gradle.configureondemand=true
 org.gradle.jvmargs=-Xmx4096m
-
-toolsVersion=0.14.6-kotlin-1.8.20
-
-
 org.gradle.parallel=true
 org.gradle.workers.max=4
+toolsVersion=0.15.2-kotlin-1.9.22
+#kotlin.experimental.tryK2=true
+#kscience.wasm.disabled=true
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index fae08049a..48c0a02ca 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/kmath-ast/README.md b/kmath-ast/README.md
index d85a18e1c..48ffa4502 100644
--- a/kmath-ast/README.md
+++ b/kmath-ast/README.md
@@ -10,19 +10,8 @@ Extensions to MST API: transformations, dynamic compilation and visualization.
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-ast:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-ast:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-ast:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -31,27 +20,33 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-ast:0.4.0-dev-1")
+    implementation("space.kscience:kmath-ast:0.4.0")
 }
 ```
 
 ## Parsing expressions
 
-In this module there is a parser from human-readable strings like `"x^3-x+3"` (in the more specific [grammar](reference/ArithmeticsEvaluator.g4)) to MST instances.
+In this module there is a parser from human-readable strings like `"x^3-x+3"` (in the more
+specific [grammar](reference/ArithmeticsEvaluator.g4)) to MST instances.
 
 Supported literals:
+
 1. Constants and variables (consist of latin letters, digits and underscores, can't start with digit): `x`, `_Abc2`.
 2. Numbers: `123`, `1.02`, `1e10`, `1e-10`, `1.0e+3`&mdash;all parsed either as `kotlin.Long` or `kotlin.Double`.
 
 Supported binary operators (from the highest precedence to the lowest one):
+
 1. `^`
 2. `*`, `/`
 3. `+`, `-`
 
 Supported unary operator:
+
 1. `-`, e.&nbsp;g. `-x`
 
-Arbitrary unary and binary functions are also supported: names consist of latin letters, digits and underscores, can't start with digit. Examples:
+Arbitrary unary and binary functions are also supported: names consist of latin letters, digits and underscores, can't
+start with digit. Examples:
+
 1. `sin(x)`
 2. `add(x, y)`
 
@@ -116,12 +111,15 @@ public final class CompiledExpression_-386104628_0 implements DoubleExpression {
 }
 ```
 
-Setting JVM system property `space.kscience.kmath.ast.dump.generated.classes` to `1` makes the translator dump class files to program's working directory, so they can be reviewed manually.
+Setting JVM system property `space.kscience.kmath.ast.dump.generated.classes` to `1` makes the translator dump class
+files to program's working directory, so they can be reviewed manually.
 
 #### Limitations
 
-- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class loading overhead.
-- This API is not supported by non-dynamic JVM implementations like TeaVM or GraalVM Native Image because they may not support class loaders.
+- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class
+  loading overhead.
+- This API is not supported by non-dynamic JVM implementations like TeaVM or GraalVM Native Image because they may not
+  support class loaders.
 
 ### On JS
 
@@ -199,7 +197,8 @@ public fun main() {
 
 Result LaTeX:
 
-$$\operatorname{exp}\\,\left(\sqrt{x}\right)-\frac{\frac{\operatorname{arcsin}\\,\left(2\\,x\right)}{2\times10^{10}+x^{3}}}{12}+x^{2/3}$$
+$$\operatorname{exp}\\,\left(\sqrt{x}\right)-\frac{\frac{\operatorname{arcsin}\\,\left(2\\,x\right)
+}{2\times10^{10}+x^{3}}}{12}+x^{2/3}$$
 
 Result MathML (can be used with MathJax or other renderers):
 
diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts
index 7cdb745f0..a770912f3 100644
--- a/kmath-ast/build.gradle.kts
+++ b/kmath-ast/build.gradle.kts
@@ -2,7 +2,7 @@ plugins {
     id("space.kscience.gradle.mpp")
 }
 
-kscience{
+kscience {
     jvm()
     js()
     native()
@@ -22,7 +22,7 @@ kscience{
         implementation(npm("js-base64", "3.6.1"))
     }
 
-    dependencies(jvmMain){
+    dependencies(jvmMain) {
         implementation("org.ow2.asm:asm-commons:9.2")
     }
 
diff --git a/kmath-ast/docs/README-TEMPLATE.md b/kmath-ast/docs/README-TEMPLATE.md
index 96bbfbf5a..70d6eb9a4 100644
--- a/kmath-ast/docs/README-TEMPLATE.md
+++ b/kmath-ast/docs/README-TEMPLATE.md
@@ -8,21 +8,27 @@ ${artifact}
 
 ## Parsing expressions
 
-In this module there is a parser from human-readable strings like `"x^3-x+3"` (in the more specific [grammar](reference/ArithmeticsEvaluator.g4)) to MST instances.
+In this module there is a parser from human-readable strings like `"x^3-x+3"` (in the more
+specific [grammar](reference/ArithmeticsEvaluator.g4)) to MST instances.
 
 Supported literals:
+
 1. Constants and variables (consist of latin letters, digits and underscores, can't start with digit): `x`, `_Abc2`.
 2. Numbers: `123`, `1.02`, `1e10`, `1e-10`, `1.0e+3`&mdash;all parsed either as `kotlin.Long` or `kotlin.Double`.
 
 Supported binary operators (from the highest precedence to the lowest one):
+
 1. `^`
 2. `*`, `/`
 3. `+`, `-`
 
 Supported unary operator:
+
 1. `-`, e.&nbsp;g. `-x`
 
-Arbitrary unary and binary functions are also supported: names consist of latin letters, digits and underscores, can't start with digit. Examples:
+Arbitrary unary and binary functions are also supported: names consist of latin letters, digits and underscores, can't
+start with digit. Examples:
+
 1. `sin(x)`
 2. `add(x, y)`
 
@@ -87,12 +93,15 @@ public final class CompiledExpression_-386104628_0 implements DoubleExpression {
 }
 ```
 
-Setting JVM system property `space.kscience.kmath.ast.dump.generated.classes` to `1` makes the translator dump class files to program's working directory, so they can be reviewed manually.
+Setting JVM system property `space.kscience.kmath.ast.dump.generated.classes` to `1` makes the translator dump class
+files to program's working directory, so they can be reviewed manually.
 
 #### Limitations
 
-- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class loading overhead.
-- This API is not supported by non-dynamic JVM implementations like TeaVM or GraalVM Native Image because they may not support class loaders.
+- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class
+  loading overhead.
+- This API is not supported by non-dynamic JVM implementations like TeaVM or GraalVM Native Image because they may not
+  support class loaders.
 
 ### On JS
 
@@ -170,7 +179,8 @@ public fun main() {
 
 Result LaTeX:
 
-$$\operatorname{exp}\\,\left(\sqrt{x}\right)-\frac{\frac{\operatorname{arcsin}\\,\left(2\\,x\right)}{2\times10^{10}+x^{3}}}{12}+x^{2/3}$$
+$$\operatorname{exp}\\,\left(\sqrt{x}\right)-\frac{\frac{\operatorname{arcsin}\\,\left(2\\,x\right)
+}{2\times10^{10}+x^{3}}}{12}+x^{2/3}$$
 
 Result MathML (can be used with MathJax or other renderers):
 
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt
index e82f7a3ab..3fdbb52b0 100644
--- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt
@@ -1,10 +1,12 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.ast
 
+import space.kscience.attributes.SafeType
+import space.kscience.attributes.WithType
 import space.kscience.kmath.expressions.Expression
 import space.kscience.kmath.expressions.Symbol
 import space.kscience.kmath.operations.Algebra
@@ -15,7 +17,7 @@ import space.kscience.kmath.operations.NumericAlgebra
  *
  * @param T the type.
  */
-public sealed interface TypedMst<T> {
+public sealed interface TypedMst<T> : WithType<T> {
     /**
      * A node containing a unary operation.
      *
@@ -24,8 +26,13 @@ public sealed interface TypedMst<T> {
      * @property function The function implementing this operation.
      * @property value The argument of this operation.
      */
-    public class Unary<T>(public val operation: String, public val function: (T) -> T, public val value: TypedMst<T>) :
-        TypedMst<T> {
+    public class Unary<T>(
+        public val operation: String,
+        public val function: (T) -> T,
+        public val value: TypedMst<T>,
+    ) : TypedMst<T> {
+        override val type: SafeType<T> get() = value.type
+
         override fun equals(other: Any?): Boolean {
             if (this === other) return true
             if (other == null || this::class != other::class) return false
@@ -59,6 +66,13 @@ public sealed interface TypedMst<T> {
         public val left: TypedMst<T>,
         public val right: TypedMst<T>,
     ) : TypedMst<T> {
+
+        init {
+            require(left.type == right.type) { "Left and right expressions must be of the same type" }
+        }
+
+        override val type: SafeType<T> get() = left.type
+
         override fun equals(other: Any?): Boolean {
             if (this === other) return true
             if (other == null || this::class != other::class) return false
@@ -89,7 +103,12 @@ public sealed interface TypedMst<T> {
      * @property value The held value.
      * @property number The number this value corresponds.
      */
-    public class Constant<T>(public val value: T, public val number: Number?) : TypedMst<T> {
+    public class Constant<T>(
+        override val type: SafeType<T>,
+        public val value: T,
+        public val number: Number?,
+    ) : TypedMst<T> {
+
         override fun equals(other: Any?): Boolean {
             if (this === other) return true
             if (other == null || this::class != other::class) return false
@@ -114,7 +133,7 @@ public sealed interface TypedMst<T> {
      * @param T the type.
      * @property symbol The symbol of the variable.
      */
-    public class Variable<T>(public val symbol: Symbol) : TypedMst<T> {
+    public class Variable<T>(override val type: SafeType<T>, public val symbol: Symbol) : TypedMst<T> {
         override fun equals(other: Any?): Boolean {
             if (this === other) return true
             if (other == null || this::class != other::class) return false
@@ -167,6 +186,7 @@ public fun <T> TypedMst<T>.interpret(algebra: Algebra<T>, vararg arguments: Pair
 /**
  * Interpret this [TypedMst] node as expression.
  */
-public fun <T : Any> TypedMst<T>.toExpression(algebra: Algebra<T>): Expression<T> = Expression { arguments ->
-    interpret(algebra, arguments)
-}
+public fun <T : Any> TypedMst<T>.toExpression(algebra: Algebra<T>): Expression<T> =
+    Expression(algebra.type) { arguments ->
+        interpret(algebra, arguments)
+    }
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt
index 8fc5a6aaf..18c7fc2b1 100644
--- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -16,6 +16,7 @@ import space.kscience.kmath.operations.bindSymbolOrNull
  */
 public fun <T> MST.evaluateConstants(algebra: Algebra<T>): TypedMst<T> = when (this) {
     is MST.Numeric -> TypedMst.Constant(
+        algebra.type,
         (algebra as? NumericAlgebra<T>)?.number(value) ?: error("Numeric nodes are not supported by $algebra"),
         value,
     )
@@ -27,7 +28,7 @@ public fun <T> MST.evaluateConstants(algebra: Algebra<T>): TypedMst<T> = when (t
                 arg.value,
             )
 
-            TypedMst.Constant(value, if (value is Number) value else null)
+            TypedMst.Constant(algebra.type, value, if (value is Number) value else null)
         }
 
         else -> TypedMst.Unary(operation, algebra.unaryOperationFunction(operation), arg)
@@ -59,7 +60,7 @@ public fun <T> MST.evaluateConstants(algebra: Algebra<T>): TypedMst<T> = when (t
                     )
                 }
 
-                TypedMst.Constant(value, if (value is Number) value else null)
+                TypedMst.Constant(algebra.type, value, if (value is Number) value else null)
             }
 
             algebra is NumericAlgebra && left is TypedMst.Constant && left.number != null -> TypedMst.Binary(
@@ -84,8 +85,8 @@ public fun <T> MST.evaluateConstants(algebra: Algebra<T>): TypedMst<T> = when (t
         val boundSymbol = algebra.bindSymbolOrNull(this)
 
         if (boundSymbol != null)
-            TypedMst.Constant(boundSymbol, if (boundSymbol is Number) boundSymbol else null)
+            TypedMst.Constant(algebra.type, boundSymbol, if (boundSymbol is Number) boundSymbol else null)
         else
-            TypedMst.Variable(this)
+            TypedMst.Variable(algebra.type, this)
     }
 }
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt
index 2c9a2a9ad..40bc60f4d 100644
--- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt
index 5a338afed..89464af32 100644
--- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt
index bfd9aeef9..8e6cada95 100644
--- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt
index f88a5b319..4590cebea 100644
--- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt
index 0196be3b6..8cc29b993 100644
--- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt
index 16957bdd2..8e0b00d10 100644
--- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt
index 4deffc83c..d9eb3ba29 100644
--- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -426,11 +426,13 @@ public class InverseTrigonometricOperations(operations: Collection<String>?) : U
          * The default instance configured with [TrigonometricOperations.ACOS_OPERATION],
          * [TrigonometricOperations.ASIN_OPERATION], [TrigonometricOperations.ATAN_OPERATION].
          */
-        public val Default: InverseTrigonometricOperations = InverseTrigonometricOperations(setOf(
-            TrigonometricOperations.ACOS_OPERATION,
-            TrigonometricOperations.ASIN_OPERATION,
-            TrigonometricOperations.ATAN_OPERATION,
-        ))
+        public val Default: InverseTrigonometricOperations = InverseTrigonometricOperations(
+            setOf(
+                TrigonometricOperations.ACOS_OPERATION,
+                TrigonometricOperations.ASIN_OPERATION,
+                TrigonometricOperations.ATAN_OPERATION,
+            )
+        )
     }
 }
 
@@ -452,10 +454,12 @@ public class InverseHyperbolicOperations(operations: Collection<String>?) : Unar
          * The default instance configured with [ExponentialOperations.ACOSH_OPERATION],
          * [ExponentialOperations.ASINH_OPERATION], and [ExponentialOperations.ATANH_OPERATION].
          */
-        public val Default: InverseHyperbolicOperations = InverseHyperbolicOperations(setOf(
-            ExponentialOperations.ACOSH_OPERATION,
-            ExponentialOperations.ASINH_OPERATION,
-            ExponentialOperations.ATANH_OPERATION,
-        ))
+        public val Default: InverseHyperbolicOperations = InverseHyperbolicOperations(
+            setOf(
+                ExponentialOperations.ACOSH_OPERATION,
+                ExponentialOperations.ASINH_OPERATION,
+                ExponentialOperations.ATANH_OPERATION,
+            )
+        )
     }
 }
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt
index dce99cc5a..b3844728b 100644
--- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt
index 0d26621d3..dae330916 100644
--- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt
index 3400db0f8..b2fe94589 100644
--- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt
+++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -9,8 +9,8 @@ import space.kscience.kmath.expressions.MstField
 import space.kscience.kmath.expressions.MstRing
 import space.kscience.kmath.expressions.Symbol.Companion.x
 import space.kscience.kmath.expressions.interpret
-import space.kscience.kmath.operations.DoubleField
-import space.kscience.kmath.operations.IntRing
+import space.kscience.kmath.operations.Float64Field
+import space.kscience.kmath.operations.Int32Ring
 import space.kscience.kmath.operations.invoke
 import kotlin.test.Test
 import kotlin.test.assertEquals
@@ -32,8 +32,8 @@ internal class TestCompilerConsistencyWithInterpreter {
         }
 
         assertEquals(
-            mst.interpret(IntRing, x to 3),
-            mst.compile(IntRing, x to 3),
+            mst.interpret(Int32Ring, x to 3),
+            mst.compile(Int32Ring, x to 3),
         )
     }
 
@@ -48,8 +48,8 @@ internal class TestCompilerConsistencyWithInterpreter {
         }
 
         assertEquals(
-            mst.interpret(DoubleField, x to 2.0),
-            mst.compile(DoubleField, x to 2.0),
+            mst.interpret(Float64Field, x to 2.0),
+            mst.compile(Float64Field, x to 2.0),
         )
     }
 }
diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt
index bf56b80a6..0fb3002f1 100644
--- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt
+++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,7 +8,7 @@ package space.kscience.kmath.ast
 import space.kscience.kmath.expressions.MstExtendedField
 import space.kscience.kmath.expressions.Symbol.Companion.x
 import space.kscience.kmath.expressions.invoke
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.invoke
 import kotlin.test.Test
 import kotlin.test.assertEquals
@@ -16,73 +16,73 @@ import kotlin.test.assertEquals
 internal class TestCompilerOperations {
     @Test
     fun testUnaryPlus() = runCompilerTest {
-        val expr = MstExtendedField { +x }.compileToExpression(DoubleField)
+        val expr = MstExtendedField { +x }.compileToExpression(Float64Field)
         assertEquals(2.0, expr(x to 2.0))
     }
 
     @Test
     fun testUnaryMinus() = runCompilerTest {
-        val expr = MstExtendedField { -x }.compileToExpression(DoubleField)
+        val expr = MstExtendedField { -x }.compileToExpression(Float64Field)
         assertEquals(-2.0, expr(x to 2.0))
     }
 
     @Test
     fun testAdd() = runCompilerTest {
-        val expr = MstExtendedField { x + x }.compileToExpression(DoubleField)
+        val expr = MstExtendedField { x + x }.compileToExpression(Float64Field)
         assertEquals(4.0, expr(x to 2.0))
     }
 
     @Test
     fun testSine() = runCompilerTest {
-        val expr = MstExtendedField { sin(x) }.compileToExpression(DoubleField)
+        val expr = MstExtendedField { sin(x) }.compileToExpression(Float64Field)
         assertEquals(0.0, expr(x to 0.0))
     }
 
     @Test
     fun testCosine() = runCompilerTest {
-        val expr = MstExtendedField { cos(x) }.compileToExpression(DoubleField)
+        val expr = MstExtendedField { cos(x) }.compileToExpression(Float64Field)
         assertEquals(1.0, expr(x to 0.0))
     }
 
     @Test
     fun testTangent() = runCompilerTest {
-        val expr = MstExtendedField { tan(x) }.compileToExpression(DoubleField)
+        val expr = MstExtendedField { tan(x) }.compileToExpression(Float64Field)
         assertEquals(0.0, expr(x to 0.0))
     }
 
     @Test
     fun testArcSine() = runCompilerTest {
-        val expr = MstExtendedField { asin(x) }.compileToExpression(DoubleField)
+        val expr = MstExtendedField { asin(x) }.compileToExpression(Float64Field)
         assertEquals(0.0, expr(x to 0.0))
     }
 
     @Test
     fun testArcCosine() = runCompilerTest {
-        val expr = MstExtendedField { acos(x) }.compileToExpression(DoubleField)
+        val expr = MstExtendedField { acos(x) }.compileToExpression(Float64Field)
         assertEquals(0.0, expr(x to 1.0))
     }
 
     @Test
     fun testAreaHyperbolicSine() = runCompilerTest {
-        val expr = MstExtendedField { asinh(x) }.compileToExpression(DoubleField)
+        val expr = MstExtendedField { asinh(x) }.compileToExpression(Float64Field)
         assertEquals(0.0, expr(x to 0.0))
     }
 
     @Test
     fun testSubtract() = runCompilerTest {
-        val expr = MstExtendedField { x - x }.compileToExpression(DoubleField)
+        val expr = MstExtendedField { x - x }.compileToExpression(Float64Field)
         assertEquals(0.0, expr(x to 2.0))
     }
 
     @Test
     fun testDivide() = runCompilerTest {
-        val expr = MstExtendedField { x / x }.compileToExpression(DoubleField)
+        val expr = MstExtendedField { x / x }.compileToExpression(Float64Field)
         assertEquals(1.0, expr(x to 2.0))
     }
 
     @Test
     fun testPower() = runCompilerTest {
-        val expr = MstExtendedField { x pow 2 }.compileToExpression(DoubleField)
+        val expr = MstExtendedField { x pow 2 }.compileToExpression(Float64Field)
         assertEquals(4.0, expr(x to 2.0))
     }
 }
diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt
index f23d36240..6fc3341b6 100644
--- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt
+++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -9,8 +9,8 @@ import space.kscience.kmath.expressions.MstRing
 import space.kscience.kmath.expressions.Symbol.Companion.x
 import space.kscience.kmath.expressions.Symbol.Companion.y
 import space.kscience.kmath.expressions.invoke
-import space.kscience.kmath.operations.DoubleField
-import space.kscience.kmath.operations.IntRing
+import space.kscience.kmath.operations.Float64Field
+import space.kscience.kmath.operations.Int32Ring
 import space.kscience.kmath.operations.invoke
 import kotlin.test.Test
 import kotlin.test.assertEquals
@@ -19,25 +19,25 @@ import kotlin.test.assertFailsWith
 internal class TestCompilerVariables {
     @Test
     fun testNoVariables() = runCompilerTest {
-        val expr = "0".parseMath().compileToExpression(DoubleField)
+        val expr = "0".parseMath().compileToExpression(Float64Field)
         assertEquals(0.0, expr(), 0.0001)
     }
 
     @Test
     fun testOneVariable() = runCompilerTest {
-        val expr = MstRing { x }.compileToExpression(IntRing)
+        val expr = MstRing { x }.compileToExpression(Int32Ring)
         assertEquals(1, expr(x to 1))
     }
 
     @Test
     fun testTwoVariables() = runCompilerTest {
-        val expr = "y+x/y+x".parseMath().compileToExpression(DoubleField)
+        val expr = "y+x/y+x".parseMath().compileToExpression(Float64Field)
         assertEquals(8.0, expr(x to 4.0, y to 2.0))
     }
 
     @Test
     fun testUndefinedVariableFails() = runCompilerTest {
-        val expr = MstRing { x }.compileToExpression(IntRing)
+        val expr = MstRing { x }.compileToExpression(Int32Ring)
         assertFailsWith<NoSuchElementException> { expr() }
     }
 }
diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt
index 95b804455..74fd4b56c 100644
--- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt
+++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt
@@ -1,13 +1,13 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.ast
 
-import space.kscience.kmath.operations.ByteRing
-import space.kscience.kmath.operations.DoubleField
-import space.kscience.kmath.operations.IntRing
+import space.kscience.kmath.operations.Float64Field
+import space.kscience.kmath.operations.Int32Ring
+import space.kscience.kmath.operations.Int8Ring
 import space.kscience.kmath.operations.pi
 import kotlin.test.Test
 import kotlin.test.assertEquals
@@ -17,36 +17,36 @@ internal class TestFolding {
     @Test
     fun foldUnary() = assertEquals(
         -1,
-        ("-(1)".parseMath().evaluateConstants(IntRing) as? TypedMst.Constant<Int> ?: fail()).value,
+        ("-(1)".parseMath().evaluateConstants(Int32Ring) as? TypedMst.Constant<Int> ?: fail()).value,
     )
 
     @Test
     fun foldDeepUnary() = assertEquals(
         1,
-        ("-(-(1))".parseMath().evaluateConstants(IntRing) as? TypedMst.Constant<Int> ?: fail()).value,
+        ("-(-(1))".parseMath().evaluateConstants(Int32Ring) as? TypedMst.Constant<Int> ?: fail()).value,
     )
 
     @Test
     fun foldBinary() = assertEquals(
         2,
-        ("1*2".parseMath().evaluateConstants(IntRing) as? TypedMst.Constant<Int> ?: fail()).value,
+        ("1*2".parseMath().evaluateConstants(Int32Ring) as? TypedMst.Constant<Int> ?: fail()).value,
     )
 
     @Test
     fun foldDeepBinary() = assertEquals(
         10,
-        ("1*2*5".parseMath().evaluateConstants(IntRing) as? TypedMst.Constant<Int> ?: fail()).value,
+        ("1*2*5".parseMath().evaluateConstants(Int32Ring) as? TypedMst.Constant<Int> ?: fail()).value,
     )
 
     @Test
     fun foldSymbol() = assertEquals(
-        DoubleField.pi,
-        ("pi".parseMath().evaluateConstants(DoubleField) as? TypedMst.Constant<Double> ?: fail()).value,
+        Float64Field.pi,
+        ("pi".parseMath().evaluateConstants(Float64Field) as? TypedMst.Constant<Double> ?: fail()).value,
     )
 
     @Test
     fun foldNumeric() = assertEquals(
         42.toByte(),
-        ("42".parseMath().evaluateConstants(ByteRing) as? TypedMst.Constant<Byte> ?: fail()).value,
+        ("42".parseMath().evaluateConstants(Int8Ring) as? TypedMst.Constant<Byte> ?: fail()).value,
     )
 }
diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt
index d3c203903..9ed6fa3f4 100644
--- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt
+++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -9,7 +9,8 @@ import space.kscience.kmath.complex.Complex
 import space.kscience.kmath.complex.ComplexField
 import space.kscience.kmath.expressions.interpret
 import space.kscience.kmath.operations.Algebra
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
+import space.kscience.kmath.structures.MutableBufferFactory
 import kotlin.test.Test
 import kotlin.test.assertEquals
 
@@ -32,13 +33,15 @@ internal class TestParser {
     @Test
     fun evaluateMstUnary() {
         val mst = "sin(0)".parseMath()
-        val res = mst.interpret(DoubleField)
+        val res = mst.interpret(Float64Field)
         assertEquals(0.0, res)
     }
 
     @Test
     fun evaluateMstBinary() {
         val magicalAlgebra = object : Algebra<String> {
+            override val bufferFactory: MutableBufferFactory<String> get() = MutableBufferFactory()
+
             override fun bindSymbolOrNull(value: String): String = value
 
             override fun unaryOperationFunction(operation: String): (arg: String) -> String {
diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt
index 4b3631663..227c0844a 100644
--- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt
+++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt
@@ -1,12 +1,12 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.ast
 
 import space.kscience.kmath.expressions.interpret
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import kotlin.test.Test
 import kotlin.test.assertEquals
 
@@ -36,6 +36,6 @@ internal class TestParserPrecedence {
     fun test8(): Unit = assertEquals(18.0, "2*2^3+2".parseMath().interpret(f))
 
     private companion object {
-        private val f = DoubleField
+        private val f = Float64Field
     }
 }
diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt
index 7b5ec5765..6ccf73232 100644
--- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt
+++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -17,7 +17,8 @@ internal class TestFeatures {
     fun printNumeric() {
         val num = object : Number() {
             override fun toByte(): Byte = throw UnsupportedOperationException()
-            override fun toChar(): Char = throw UnsupportedOperationException()
+
+            //            override fun toChar(): Char = throw UnsupportedOperationException()
             override fun toDouble(): Double = throw UnsupportedOperationException()
             override fun toFloat(): Float = throw UnsupportedOperationException()
             override fun toInt(): Int = throw UnsupportedOperationException()
diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt
index 66c0ae1ae..12c11f89c 100644
--- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt
+++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt
index 8bc014c54..2a5857069 100644
--- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt
+++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -81,8 +81,10 @@ internal class TestMathML {
 
     @Test
     fun radicalWithIndex() =
-        testMathML(RadicalWithIndexSyntax("", SymbolSyntax("x"), SymbolSyntax("y")),
-            "<mroot><mrow><mi>y</mi></mrow><mrow><mi>x</mi></mrow></mroot>")
+        testMathML(
+            RadicalWithIndexSyntax("", SymbolSyntax("x"), SymbolSyntax("y")),
+            "<mroot><mrow><mi>y</mi></mrow><mrow><mi>x</mi></mrow></mroot>"
+        )
 
     @Test
     fun multiplication() {
diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt
index 306538d5d..be3d587be 100644
--- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt
+++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt
index 79f178eef..378e6647b 100644
--- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt
+++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt
index fe035c69f..ee2346b13 100644
--- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt
+++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,17 +8,17 @@ package space.kscience.kmath.ast
 import space.kscience.kmath.expressions.Expression
 import space.kscience.kmath.expressions.MST
 import space.kscience.kmath.expressions.Symbol
-import space.kscience.kmath.operations.DoubleField
-import space.kscience.kmath.operations.IntRing
+import space.kscience.kmath.operations.Float64Field
+import space.kscience.kmath.operations.Int32Ring
 
 internal interface CompilerTestContext {
-    fun MST.compileToExpression(algebra: IntRing): Expression<Int>
-    fun MST.compile(algebra: IntRing, arguments: Map<Symbol, Int>): Int
-    fun MST.compile(algebra: IntRing, vararg arguments: Pair<Symbol, Int>): Int = compile(algebra, mapOf(*arguments))
-    fun MST.compileToExpression(algebra: DoubleField): Expression<Double>
-    fun MST.compile(algebra: DoubleField, arguments: Map<Symbol, Double>): Double
+    fun MST.compileToExpression(algebra: Int32Ring): Expression<Int>
+    fun MST.compile(algebra: Int32Ring, arguments: Map<Symbol, Int>): Int
+    fun MST.compile(algebra: Int32Ring, vararg arguments: Pair<Symbol, Int>): Int = compile(algebra, mapOf(*arguments))
+    fun MST.compileToExpression(algebra: Float64Field): Expression<Double>
+    fun MST.compile(algebra: Float64Field, arguments: Map<Symbol, Double>): Double
 
-    fun MST.compile(algebra: DoubleField, vararg arguments: Pair<Symbol, Double>): Double =
+    fun MST.compile(algebra: Float64Field, vararg arguments: Pair<Symbol, Double>): Double =
         compile(algebra, mapOf(*arguments))
 }
 
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt
index f6411334c..c1842b039 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt
index 87c2df2d2..26e963af0 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -22,7 +22,7 @@ import space.kscience.kmath.operations.Algebra
 @OptIn(UnstableKMathAPI::class)
 public fun <T : Any> MST.compileToExpression(algebra: Algebra<T>): Expression<T> {
     val typed = evaluateConstants(algebra)
-    if (typed is TypedMst.Constant<T>) return Expression { typed.value }
+    if (typed is TypedMst.Constant<T>) return Expression(algebra.type) { typed.value }
 
     fun ESTreeBuilder<T>.visit(node: TypedMst<T>): BaseExpression = when (node) {
         is TypedMst.Constant -> constant(node.value)
@@ -36,7 +36,7 @@ public fun <T : Any> MST.compileToExpression(algebra: Algebra<T>): Expression<T>
         )
     }
 
-    return ESTreeBuilder { visit(typed) }.instance
+    return ESTreeBuilder(algebra.type) { visit(typed) }.instance
 }
 
 /**
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt
index 1517cdef2..f4a879d1b 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt
@@ -1,17 +1,26 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.estree.internal
 
+import space.kscience.attributes.SafeType
+import space.kscience.attributes.WithType
 import space.kscience.kmath.expressions.Expression
 import space.kscience.kmath.expressions.Symbol
 import space.kscience.kmath.internal.astring.generate
 import space.kscience.kmath.internal.estree.*
 
-internal class ESTreeBuilder<T>(val bodyCallback: ESTreeBuilder<T>.() -> BaseExpression) {
-    private class GeneratedExpression<T>(val executable: dynamic, val constants: Array<dynamic>) : Expression<T> {
+internal class ESTreeBuilder<T>(
+    override val type: SafeType<T>,
+    val bodyCallback: ESTreeBuilder<T>.() -> BaseExpression,
+) : WithType<T> {
+    private class GeneratedExpression<T>(
+        override val type: SafeType<T>,
+        val executable: dynamic,
+        val constants: Array<dynamic>,
+    ) : Expression<T> {
         @Suppress("UNUSED_VARIABLE")
         override fun invoke(arguments: Map<Symbol, T>): T {
             val e = executable
@@ -30,7 +39,7 @@ internal class ESTreeBuilder<T>(val bodyCallback: ESTreeBuilder<T>.() -> BaseExp
         )
 
         val code = generate(node)
-        GeneratedExpression(js("new Function('constants', 'arguments_0', code)"), constants.toTypedArray())
+        GeneratedExpression(type, js("new Function('constants', 'arguments_0', code)"), constants.toTypedArray())
     }
 
     private val constants = mutableListOf<Any>()
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt
index 2434788ec..ccbebff81 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt
index cc4360f8d..25721fee6 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt
index a17726c9d..bf0d06660 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt
index 8ea699837..cb4da44fe 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt
index d907a12c9..6380d9b6c 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,9 +8,8 @@
     "OVERRIDING_FINAL_MEMBER",
     "RETURN_TYPE_MISMATCH_ON_OVERRIDE",
     "CONFLICTING_OVERLOADS",
-    "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING",
     "PropertyName",
-    "ClassName",
+    "ClassName", "ENUM_CLASS_IN_EXTERNAL_DECLARATION_WARNING",
 )
 
 @file:JsModule("binaryen")
@@ -1657,27 +1656,27 @@ internal open external class Module {
     open fun `if`(
         condition: ExpressionRef,
         ifTrue: ExpressionRef,
-        ifFalse: ExpressionRef = definedExternally
+        ifFalse: ExpressionRef = definedExternally,
     ): ExpressionRef
 
     open fun loop(label: String, body: ExpressionRef): ExpressionRef
     open fun br(
         label: String,
         condition: ExpressionRef = definedExternally,
-        value: ExpressionRef = definedExternally
+        value: ExpressionRef = definedExternally,
     ): ExpressionRef
 
     open fun br_if(
         label: String,
         condition: ExpressionRef = definedExternally,
-        value: ExpressionRef = definedExternally
+        value: ExpressionRef = definedExternally,
     ): ExpressionRef
 
     open fun switch(
         labels: Array<String>,
         defaultLabel: String,
         condition: ExpressionRef,
-        value: ExpressionRef = definedExternally
+        value: ExpressionRef = definedExternally,
     ): ExpressionRef
 
     open fun call(name: String, operands: Array<ExpressionRef>, returnType: Type): ExpressionRef
@@ -1686,14 +1685,14 @@ internal open external class Module {
         target: ExpressionRef,
         operands: Array<ExpressionRef>,
         params: Type,
-        results: Type
+        results: Type,
     ): ExpressionRef
 
     open fun return_call_indirect(
         target: ExpressionRef,
         operands: Array<ExpressionRef>,
         params: Type,
-        results: Type
+        results: Type,
     ): ExpressionRef
 
     open var local: `T$2`
@@ -1731,7 +1730,7 @@ internal open external class Module {
         condition: ExpressionRef,
         ifTrue: ExpressionRef,
         ifFalse: ExpressionRef,
-        type: Type = definedExternally
+        type: Type = definedExternally,
     ): ExpressionRef
 
     open fun drop(value: ExpressionRef): ExpressionRef
@@ -1755,7 +1754,7 @@ internal open external class Module {
         externalModuleName: String,
         externalBaseName: String,
         params: Type,
-        results: Type
+        results: Type,
     )
 
     open fun addTableImport(internalName: String, externalModuleName: String, externalBaseName: String)
@@ -1764,7 +1763,7 @@ internal open external class Module {
         internalName: String,
         externalModuleName: String,
         externalBaseName: String,
-        globalType: Type
+        globalType: Type,
     )
 
     open fun addEventImport(
@@ -1773,7 +1772,7 @@ internal open external class Module {
         externalBaseName: String,
         attribute: Number,
         params: Type,
-        results: Type
+        results: Type,
     )
 
     open fun addFunctionExport(internalName: String, externalName: String): ExportRef
@@ -1787,7 +1786,7 @@ internal open external class Module {
         initial: Number,
         maximum: Number,
         funcNames: Array<Number>,
-        offset: ExpressionRef = definedExternally
+        offset: ExpressionRef = definedExternally,
     )
 
     open fun getFunctionTable(): `T$26`
@@ -1797,7 +1796,7 @@ internal open external class Module {
         exportName: String? = definedExternally,
         segments: Array<MemorySegment>? = definedExternally,
         flags: Array<Number>? = definedExternally,
-        shared: Boolean = definedExternally
+        shared: Boolean = definedExternally,
     )
 
     open fun getNumMemorySegments(): Number
@@ -1828,7 +1827,7 @@ internal open external class Module {
         expr: ExpressionRef,
         fileIndex: Number,
         lineNumber: Number,
-        columnNumber: Number
+        columnNumber: Number,
     )
 
     open fun copyExpression(expr: ExpressionRef): ExpressionRef
@@ -2232,7 +2231,7 @@ internal open external class Relooper(module: Module) {
         from: RelooperBlockRef,
         to: RelooperBlockRef,
         indexes: Array<Number>,
-        code: ExpressionRef
+        code: ExpressionRef,
     )
 
     open fun renderAndDispose(entry: RelooperBlockRef, labelHelper: Number): ExpressionRef
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt
index eebfeb6ef..f9b3654c2 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt
index a2a04da79..e87a5f380 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt
index 2dd2c08cd..db0723163 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -30,12 +30,13 @@ internal fun Identifier(name: String) = object : Identifier {
     override var name = name
 }
 
-internal fun FunctionExpression(id: Identifier?, params: Array<dynamic>, body: BlockStatement) = object : FunctionExpression {
-    override var params = params
-    override var type = "FunctionExpression"
-    override var id: Identifier? = id
-    override var body = body
-}
+internal fun FunctionExpression(id: Identifier?, params: Array<dynamic>, body: BlockStatement) =
+    object : FunctionExpression {
+        override var params = params
+        override var type = "FunctionExpression"
+        override var id: Identifier? = id
+        override var body = body
+    }
 
 internal fun BlockStatement(vararg body: dynamic) = object : BlockStatement {
     override var type = "BlockStatement"
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt
index bf4a25367..a05f57f7f 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt
index ced165a3a..496df7e67 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt
index 2c0dc9de1..9320243d8 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt
index f20e2d865..ee17edbc8 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -91,6 +91,6 @@ internal typealias Extract<T, U> = Any
 internal external interface PromiseLike<T> {
     fun then(
         onfulfilled: ((value: T) -> Any?)? = definedExternally,
-        onrejected: ((reason: Any) -> Any?)? = definedExternally
+        onrejected: ((reason: Any) -> Any?)? = definedExternally,
     ): PromiseLike<dynamic /* TResult1 | TResult2 */>
 }
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt
index 873a5e1d2..c3e79c864 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -15,11 +15,11 @@
 
 package space.kscience.kmath.internal.webassembly
 
-import space.kscience.kmath.internal.tsstdlib.PromiseLike
 import org.khronos.webgl.ArrayBuffer
 import org.khronos.webgl.ArrayBufferView
 import org.khronos.webgl.Uint8Array
 import org.w3c.fetch.Response
+import space.kscience.kmath.internal.tsstdlib.PromiseLike
 import kotlin.js.Promise
 
 @Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE")
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt
index ba86e977b..ad97c259d 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt
index 1908f0659..18ef35c4b 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -86,7 +86,7 @@ internal sealed class WasmBuilder<T : Number, out E : Expression<T>>(
 
 @UnstableKMathAPI
 internal class DoubleWasmBuilder(target: TypedMst<Double>) :
-    WasmBuilder<Double, DoubleExpression>(f64, DoubleField, target) {
+    WasmBuilder<Double, DoubleExpression>(f64, Float64Field, target) {
     override val instance by lazy {
         object : DoubleExpression {
             override val indexer = SimpleSymbolIndexer(keys)
@@ -131,7 +131,7 @@ internal class DoubleWasmBuilder(target: TypedMst<Double>) :
 }
 
 @UnstableKMathAPI
-internal class IntWasmBuilder(target: TypedMst<Int>) : WasmBuilder<Int, IntExpression>(i32, IntRing, target) {
+internal class IntWasmBuilder(target: TypedMst<Int>) : WasmBuilder<Int, IntExpression>(i32, Int32Ring, target) {
     override val instance by lazy {
         object : IntExpression {
             override val indexer = SimpleSymbolIndexer(keys)
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt
index d60f24247..63cda9756 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt
index acb26f918..ceb1ad69d 100644
--- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt
+++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -11,8 +11,8 @@ import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.ast.TypedMst
 import space.kscience.kmath.ast.evaluateConstants
 import space.kscience.kmath.expressions.*
-import space.kscience.kmath.operations.DoubleField
-import space.kscience.kmath.operations.IntRing
+import space.kscience.kmath.operations.Float64Field
+import space.kscience.kmath.operations.Int32Ring
 import space.kscience.kmath.wasm.internal.DoubleWasmBuilder
 import space.kscience.kmath.wasm.internal.IntWasmBuilder
 
@@ -22,7 +22,7 @@ import space.kscience.kmath.wasm.internal.IntWasmBuilder
  * @author Iaroslav Postovalov
  */
 @UnstableKMathAPI
-public fun MST.compileToExpression(algebra: IntRing): IntExpression {
+public fun MST.compileToExpression(algebra: Int32Ring): IntExpression {
     val typed = evaluateConstants(algebra)
 
     return if (typed is TypedMst.Constant) object : IntExpression {
@@ -39,7 +39,7 @@ public fun MST.compileToExpression(algebra: IntRing): IntExpression {
  * @author Iaroslav Postovalov
  */
 @UnstableKMathAPI
-public fun MST.compile(algebra: IntRing, arguments: Map<Symbol, Int>): Int =
+public fun MST.compile(algebra: Int32Ring, arguments: Map<Symbol, Int>): Int =
     compileToExpression(algebra)(arguments)
 
 
@@ -49,7 +49,7 @@ public fun MST.compile(algebra: IntRing, arguments: Map<Symbol, Int>): Int =
  * @author Iaroslav Postovalov
  */
 @UnstableKMathAPI
-public fun MST.compile(algebra: IntRing, vararg arguments: Pair<Symbol, Int>): Int =
+public fun MST.compile(algebra: Int32Ring, vararg arguments: Pair<Symbol, Int>): Int =
     compileToExpression(algebra)(*arguments)
 
 /**
@@ -58,7 +58,7 @@ public fun MST.compile(algebra: IntRing, vararg arguments: Pair<Symbol, Int>): I
  * @author Iaroslav Postovalov
  */
 @UnstableKMathAPI
-public fun MST.compileToExpression(algebra: DoubleField): Expression<Double> {
+public fun MST.compileToExpression(algebra: Float64Field): Expression<Double> {
     val typed = evaluateConstants(algebra)
 
     return if (typed is TypedMst.Constant) object : DoubleExpression {
@@ -76,7 +76,7 @@ public fun MST.compileToExpression(algebra: DoubleField): Expression<Double> {
  * @author Iaroslav Postovalov
  */
 @UnstableKMathAPI
-public fun MST.compile(algebra: DoubleField, arguments: Map<Symbol, Double>): Double =
+public fun MST.compile(algebra: Float64Field, arguments: Map<Symbol, Double>): Double =
     compileToExpression(algebra)(arguments)
 
 
@@ -86,5 +86,5 @@ public fun MST.compile(algebra: DoubleField, arguments: Map<Symbol, Double>): Do
  * @author Iaroslav Postovalov
  */
 @UnstableKMathAPI
-public fun MST.compile(algebra: DoubleField, vararg arguments: Pair<Symbol, Double>): Double =
+public fun MST.compile(algebra: Float64Field, vararg arguments: Pair<Symbol, Double>): Double =
     compileToExpression(algebra)(*arguments)
diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt
index 7c397d5a0..c747adc0c 100644
--- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt
+++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -11,8 +11,8 @@ import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.expressions.Expression
 import space.kscience.kmath.expressions.MST
 import space.kscience.kmath.expressions.Symbol
-import space.kscience.kmath.operations.DoubleField
-import space.kscience.kmath.operations.IntRing
+import space.kscience.kmath.operations.Float64Field
+import space.kscience.kmath.operations.Int32Ring
 import kotlin.contracts.InvocationKind
 import kotlin.contracts.contract
 import space.kscience.kmath.estree.compile as estreeCompile
@@ -20,21 +20,22 @@ import space.kscience.kmath.estree.compileToExpression as estreeCompileToExpress
 import space.kscience.kmath.wasm.compile as wasmCompile
 import space.kscience.kmath.wasm.compileToExpression as wasmCompileToExpression
 
+@OptIn(UnstableKMathAPI::class)
 private object WasmCompilerTestContext : CompilerTestContext {
-    override fun MST.compileToExpression(algebra: IntRing): Expression<Int> = wasmCompileToExpression(algebra)
-    override fun MST.compile(algebra: IntRing, arguments: Map<Symbol, Int>): Int = wasmCompile(algebra, arguments)
-    override fun MST.compileToExpression(algebra: DoubleField): Expression<Double> = wasmCompileToExpression(algebra)
+    override fun MST.compileToExpression(algebra: Int32Ring): Expression<Int> = wasmCompileToExpression(algebra)
+    override fun MST.compile(algebra: Int32Ring, arguments: Map<Symbol, Int>): Int = wasmCompile(algebra, arguments)
+    override fun MST.compileToExpression(algebra: Float64Field): Expression<Double> = wasmCompileToExpression(algebra)
 
-    override fun MST.compile(algebra: DoubleField, arguments: Map<Symbol, Double>): Double =
+    override fun MST.compile(algebra: Float64Field, arguments: Map<Symbol, Double>): Double =
         wasmCompile(algebra, arguments)
 }
 
 private object ESTreeCompilerTestContext : CompilerTestContext {
-    override fun MST.compileToExpression(algebra: IntRing): Expression<Int> = estreeCompileToExpression(algebra)
-    override fun MST.compile(algebra: IntRing, arguments: Map<Symbol, Int>): Int = estreeCompile(algebra, arguments)
-    override fun MST.compileToExpression(algebra: DoubleField): Expression<Double> = estreeCompileToExpression(algebra)
+    override fun MST.compileToExpression(algebra: Int32Ring): Expression<Int> = estreeCompileToExpression(algebra)
+    override fun MST.compile(algebra: Int32Ring, arguments: Map<Symbol, Int>): Int = estreeCompile(algebra, arguments)
+    override fun MST.compileToExpression(algebra: Float64Field): Expression<Double> = estreeCompileToExpression(algebra)
 
-    override fun MST.compile(algebra: DoubleField, arguments: Map<Symbol, Double>): Double =
+    override fun MST.compile(algebra: Float64Field, arguments: Map<Symbol, Double>): Double =
         estreeCompile(algebra, arguments)
 }
 
diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt
index 132f9f1bd..45b5aef5a 100644
--- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt
+++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -10,8 +10,8 @@ import space.kscience.kmath.expressions.MstExtendedField
 import space.kscience.kmath.expressions.MstRing
 import space.kscience.kmath.expressions.invoke
 import space.kscience.kmath.expressions.symbol
-import space.kscience.kmath.operations.DoubleField
-import space.kscience.kmath.operations.IntRing
+import space.kscience.kmath.operations.Float64Field
+import space.kscience.kmath.operations.Int32Ring
 import space.kscience.kmath.operations.invoke
 import kotlin.test.Test
 import kotlin.test.assertEquals
@@ -20,20 +20,20 @@ import kotlin.test.assertEquals
 internal class TestWasmSpecific {
     @Test
     fun int() {
-        val res = MstRing { number(100000000) + number(10000000) }.compile(IntRing)
+        val res = MstRing { number(100000000) + number(10000000) }.compile(Int32Ring)
         assertEquals(110000000, res)
     }
 
     @Test
     fun real() {
-        val res = MstExtendedField { number(100000000) + number(2).pow(10) }.compile(DoubleField)
+        val res = MstExtendedField { number(100000000) + number(2).pow(10) }.compile(Float64Field)
         assertEquals(100001024.0, res)
     }
 
     @Test
     fun argsPassing() {
         val res = MstExtendedField { y + x.pow(10) }.compile(
-            DoubleField,
+            Float64Field,
             x to 2.0,
             y to 100000000.0,
         )
@@ -43,7 +43,7 @@ internal class TestWasmSpecific {
 
     @Test
     fun powFunction() {
-        val expr = MstExtendedField { x.pow(1.0 / 6.0) }.compileToExpression(DoubleField)
+        val expr = MstExtendedField { x.pow(1.0 / 6.0) }.compileToExpression(Float64Field)
         assertEquals(0.9730585187140817, expr(x to 0.8488554755054833))
     }
 
diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt
index 7094d0442..ac35562d2 100644
--- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt
+++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -13,9 +13,9 @@ import space.kscience.kmath.ast.TypedMst
 import space.kscience.kmath.ast.evaluateConstants
 import space.kscience.kmath.expressions.*
 import space.kscience.kmath.operations.Algebra
-import space.kscience.kmath.operations.DoubleField
-import space.kscience.kmath.operations.IntRing
-import space.kscience.kmath.operations.LongRing
+import space.kscience.kmath.operations.Float64Field
+import space.kscience.kmath.operations.Int32Ring
+import space.kscience.kmath.operations.Int64Ring
 
 /**
  * Compiles given MST to an Expression using AST compiler.
@@ -29,7 +29,7 @@ import space.kscience.kmath.operations.LongRing
 @PublishedApi
 internal fun <T : Any> MST.compileWith(type: Class<T>, algebra: Algebra<T>): Expression<T> {
     val typed = evaluateConstants(algebra)
-    if (typed is TypedMst.Constant<T>) return Expression { typed.value }
+    if (typed is TypedMst.Constant<T>) return Expression(algebra.type) { typed.value }
 
     fun GenericAsmBuilder<T>.variablesVisitor(node: TypedMst<T>): Unit = when (node) {
         is TypedMst.Unary -> variablesVisitor(node.value)
@@ -91,7 +91,7 @@ public inline fun <reified T : Any> MST.compile(algebra: Algebra<T>, vararg argu
  * @author Iaroslav Postovalov
  */
 @UnstableKMathAPI
-public fun MST.compileToExpression(algebra: IntRing): IntExpression  {
+public fun MST.compileToExpression(algebra: Int32Ring): IntExpression {
     val typed = evaluateConstants(algebra)
 
     return if (typed is TypedMst.Constant) object : IntExpression {
@@ -108,7 +108,7 @@ public fun MST.compileToExpression(algebra: IntRing): IntExpression  {
  * @author Iaroslav Postovalov
  */
 @UnstableKMathAPI
-public fun MST.compile(algebra: IntRing, arguments: Map<Symbol, Int>): Int =
+public fun MST.compile(algebra: Int32Ring, arguments: Map<Symbol, Int>): Int =
     compileToExpression(algebra)(arguments)
 
 /**
@@ -117,7 +117,7 @@ public fun MST.compile(algebra: IntRing, arguments: Map<Symbol, Int>): Int =
  * @author Iaroslav Postovalov
  */
 @UnstableKMathAPI
-public fun MST.compile(algebra: IntRing, vararg arguments: Pair<Symbol, Int>): Int =
+public fun MST.compile(algebra: Int32Ring, vararg arguments: Pair<Symbol, Int>): Int =
     compileToExpression(algebra)(*arguments)
 
 
@@ -127,7 +127,7 @@ public fun MST.compile(algebra: IntRing, vararg arguments: Pair<Symbol, Int>): I
  * @author Iaroslav Postovalov
  */
 @UnstableKMathAPI
-public fun MST.compileToExpression(algebra: LongRing): LongExpression {
+public fun MST.compileToExpression(algebra: Int64Ring): LongExpression {
     val typed = evaluateConstants(algebra)
 
     return if (typed is TypedMst.Constant<Long>) object : LongExpression {
@@ -144,7 +144,7 @@ public fun MST.compileToExpression(algebra: LongRing): LongExpression {
  * @author Iaroslav Postovalov
  */
 @UnstableKMathAPI
-public fun MST.compile(algebra: LongRing, arguments: Map<Symbol, Long>): Long =
+public fun MST.compile(algebra: Int64Ring, arguments: Map<Symbol, Long>): Long =
     compileToExpression(algebra)(arguments)
 
 
@@ -154,7 +154,7 @@ public fun MST.compile(algebra: LongRing, arguments: Map<Symbol, Long>): Long =
  * @author Iaroslav Postovalov
  */
 @UnstableKMathAPI
-public fun MST.compile(algebra: LongRing, vararg arguments: Pair<Symbol, Long>): Long =
+public fun MST.compile(algebra: Int64Ring, vararg arguments: Pair<Symbol, Long>): Long =
     compileToExpression(algebra)(*arguments)
 
 
@@ -164,7 +164,7 @@ public fun MST.compile(algebra: LongRing, vararg arguments: Pair<Symbol, Long>):
  * @author Iaroslav Postovalov
  */
 @UnstableKMathAPI
-public fun MST.compileToExpression(algebra: DoubleField): DoubleExpression {
+public fun MST.compileToExpression(algebra: Float64Field): DoubleExpression {
     val typed = evaluateConstants(algebra)
 
     return if (typed is TypedMst.Constant) object : DoubleExpression {
@@ -182,7 +182,7 @@ public fun MST.compileToExpression(algebra: DoubleField): DoubleExpression {
  * @author Iaroslav Postovalov
  */
 @UnstableKMathAPI
-public fun MST.compile(algebra: DoubleField, arguments: Map<Symbol, Double>): Double =
+public fun MST.compile(algebra: Float64Field, arguments: Map<Symbol, Double>): Double =
     compileToExpression(algebra)(arguments)
 
 /**
@@ -191,5 +191,5 @@ public fun MST.compile(algebra: DoubleField, arguments: Map<Symbol, Double>): Do
  * @author Iaroslav Postovalov
  */
 @UnstableKMathAPI
-public fun MST.compile(algebra: DoubleField, vararg arguments: Pair<Symbol, Double>): Double =
+public fun MST.compile(algebra: Float64Field, vararg arguments: Pair<Symbol, Double>): Double =
     compileToExpression(algebra)(*arguments)
diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt
index e1fd455fd..aa7e093a5 100644
--- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt
+++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt
index acae45d87..4c20afde5 100644
--- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt
+++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -13,9 +13,6 @@ import space.kscience.kmath.expressions.*
 import java.lang.invoke.MethodHandles
 import java.lang.invoke.MethodType
 import java.nio.file.Paths
-import java.util.stream.Collectors.toMap
-import kotlin.contracts.InvocationKind
-import kotlin.contracts.contract
 import kotlin.io.path.writeBytes
 
 /**
@@ -283,7 +280,6 @@ internal class GenericAsmBuilder<T>(
     fun loadVariable(name: Symbol): Unit = invokeMethodVisitor.load(2 + argumentsLocals.indexOf(name), tType)
 
     inline fun buildCall(function: Function<T>, parameters: GenericAsmBuilder<T>.() -> Unit) {
-        contract { callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) }
         val `interface` = function.javaClass.interfaces.first { Function::class.java in it.interfaces }
 
         val arity = `interface`.methods.find { it.name == "invoke" }?.parameterCount
diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt
index a3e5b7522..3f003bb09 100644
--- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt
+++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -332,7 +332,7 @@ internal sealed class PrimitiveAsmBuilder<T : Number, out E : Expression<T>>(
     private fun visitVariables(
         node: TypedMst<T>,
         arrayMode: Boolean,
-        alreadyLoaded: MutableList<Symbol> = mutableListOf()
+        alreadyLoaded: MutableList<Symbol> = mutableListOf(),
     ): Unit = when (node) {
         is TypedMst.Variable -> if (node.symbol !in alreadyLoaded) {
             alreadyLoaded += node.symbol
@@ -382,7 +382,7 @@ internal sealed class PrimitiveAsmBuilder<T : Number, out E : Expression<T>>(
 
 @UnstableKMathAPI
 internal class DoubleAsmBuilder(target: TypedMst<Double>) : PrimitiveAsmBuilder<Double, DoubleExpression>(
-    DoubleField,
+    Float64Field,
     java.lang.Double::class.java,
     java.lang.Double.TYPE,
     DoubleExpression::class.java,
@@ -457,7 +457,7 @@ internal class DoubleAsmBuilder(target: TypedMst<Double>) : PrimitiveAsmBuilder<
 @UnstableKMathAPI
 internal class IntAsmBuilder(target: TypedMst<Int>) :
     PrimitiveAsmBuilder<Int, IntExpression>(
-        IntRing,
+        Int32Ring,
         Integer::class.java,
         Integer.TYPE,
         IntExpression::class.java,
@@ -487,7 +487,7 @@ internal class IntAsmBuilder(target: TypedMst<Int>) :
 
 @UnstableKMathAPI
 internal class LongAsmBuilder(target: TypedMst<Long>) : PrimitiveAsmBuilder<Long, LongExpression>(
-    LongRing,
+    Int64Ring,
     java.lang.Long::class.java,
     java.lang.Long.TYPE,
     LongExpression::class.java,
diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt
index b3ccfdc0c..e0d3a0ef4 100644
--- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt
+++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,7 +8,6 @@ package space.kscience.kmath.asm.internal
 import org.objectweb.asm.*
 import org.objectweb.asm.commons.InstructionAdapter
 import space.kscience.kmath.expressions.Expression
-import space.kscience.kmath.expressions.MST
 import kotlin.contracts.InvocationKind
 import kotlin.contracts.contract
 
diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt
index 6459f4dcf..392854541 100644
--- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt
+++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt
index ec66be830..745dced45 100644
--- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt
+++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt
index be890273d..f06137c4a 100644
--- a/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt
+++ b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -10,34 +10,34 @@ import space.kscience.kmath.expressions.Expression
 import space.kscience.kmath.expressions.MST
 import space.kscience.kmath.expressions.Symbol
 import space.kscience.kmath.operations.Algebra
-import space.kscience.kmath.operations.DoubleField
-import space.kscience.kmath.operations.IntRing
+import space.kscience.kmath.operations.Float64Field
+import space.kscience.kmath.operations.Int32Ring
 import kotlin.contracts.InvocationKind
 import kotlin.contracts.contract
 import space.kscience.kmath.asm.compile as asmCompile
 import space.kscience.kmath.asm.compileToExpression as asmCompileToExpression
 
 private object GenericAsmCompilerTestContext : CompilerTestContext {
-    override fun MST.compileToExpression(algebra: IntRing): Expression<Int> =
+    override fun MST.compileToExpression(algebra: Int32Ring): Expression<Int> =
         asmCompileToExpression(algebra as Algebra<Int>)
 
-    override fun MST.compile(algebra: IntRing, arguments: Map<Symbol, Int>): Int =
+    override fun MST.compile(algebra: Int32Ring, arguments: Map<Symbol, Int>): Int =
         asmCompile(algebra as Algebra<Int>, arguments)
 
-    override fun MST.compileToExpression(algebra: DoubleField): Expression<Double> =
+    override fun MST.compileToExpression(algebra: Float64Field): Expression<Double> =
         asmCompileToExpression(algebra as Algebra<Double>)
 
-    override fun MST.compile(algebra: DoubleField, arguments: Map<Symbol, Double>): Double =
+    override fun MST.compile(algebra: Float64Field, arguments: Map<Symbol, Double>): Double =
         asmCompile(algebra as Algebra<Double>, arguments)
 }
 
 @OptIn(UnstableKMathAPI::class)
 private object PrimitiveAsmCompilerTestContext : CompilerTestContext {
-    override fun MST.compileToExpression(algebra: IntRing): Expression<Int> = asmCompileToExpression(algebra)
-    override fun MST.compile(algebra: IntRing, arguments: Map<Symbol, Int>): Int = asmCompile(algebra, arguments)
-    override fun MST.compileToExpression(algebra: DoubleField): Expression<Double> = asmCompileToExpression(algebra)
+    override fun MST.compileToExpression(algebra: Int32Ring): Expression<Int> = asmCompileToExpression(algebra)
+    override fun MST.compile(algebra: Int32Ring, arguments: Map<Symbol, Int>): Int = asmCompile(algebra, arguments)
+    override fun MST.compileToExpression(algebra: Float64Field): Expression<Double> = asmCompileToExpression(algebra)
 
-    override fun MST.compile(algebra: DoubleField, arguments: Map<Symbol, Double>): Double =
+    override fun MST.compile(algebra: Float64Field, arguments: Map<Symbol, Double>): Double =
         asmCompile(algebra, arguments)
 }
 
diff --git a/kmath-ast/src/nativeMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/nativeMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt
index ec66be830..745dced45 100644
--- a/kmath-ast/src/nativeMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt
+++ b/kmath-ast/src/nativeMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ast/src/nativeTest/kotlin/space/kscience/kmath/ast/runCompilerTest.kt b/kmath-ast/src/nativeTest/kotlin/space/kscience/kmath/ast/runCompilerTest.kt
index 0674b0492..28dd12e1f 100644
--- a/kmath-ast/src/nativeTest/kotlin/space/kscience/kmath/ast/runCompilerTest.kt
+++ b/kmath-ast/src/nativeTest/kotlin/space/kscience/kmath/ast/runCompilerTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-commons/README.md b/kmath-commons/README.md
index 47b61c409..2c60f4142 100644
--- a/kmath-commons/README.md
+++ b/kmath-commons/README.md
@@ -6,19 +6,8 @@ Commons math binding for kmath
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-commons:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-commons:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-commons:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -27,6 +16,6 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-commons:0.4.0-dev-1")
+    implementation("space.kscience:kmath-commons:0.4.0")
 }
 ```
diff --git a/kmath-commons/build.gradle.kts b/kmath-commons/build.gradle.kts
index 50fef7ac8..5c2c4a304 100644
--- a/kmath-commons/build.gradle.kts
+++ b/kmath-commons/build.gradle.kts
@@ -1,17 +1,20 @@
 plugins {
-    id("space.kscience.gradle.jvm")
+    id("space.kscience.gradle.mpp")
 }
 
 description = "Commons math binding for kmath"
 
-dependencies {
-    api(project(":kmath-core"))
-    api(project(":kmath-complex"))
-    api(project(":kmath-coroutines"))
-    api(project(":kmath-optimization"))
-    api(project(":kmath-stat"))
-    api(project(":kmath-functions"))
-    api("org.apache.commons:commons-math3:3.6.1")
+kscience {
+    jvm()
+    jvmMain {
+        api(projects.kmathCore)
+        api(projects.kmathComplex)
+        api(projects.kmathCoroutines)
+        api(projects.kmathOptimization)
+        api(projects.kmathStat)
+        api(projects.kmathFunctions)
+        api("org.apache.commons:commons-math3:3.6.1")
+    }
 }
 
 readme {
diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt
similarity index 91%
rename from kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt
rename to kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt
index 38eaf8868..855de14a0 100644
--- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt
+++ b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/expressions/CmDsExpression.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,10 +8,13 @@
 package space.kscience.kmath.commons.expressions
 
 import org.apache.commons.math3.analysis.differentiation.DerivativeStructure
+import space.kscience.attributes.SafeType
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.expressions.*
+import space.kscience.kmath.operations.DoubleField
 import space.kscience.kmath.operations.ExtendedField
 import space.kscience.kmath.operations.NumbersAddOps
+import space.kscience.kmath.structures.MutableBufferFactory
 
 /**
  * A field over commons-math [DerivativeStructure].
@@ -26,6 +29,9 @@ public class CmDsField(
     bindings: Map<Symbol, Double>,
 ) : ExtendedField<DerivativeStructure>, ExpressionAlgebra<Double, DerivativeStructure>,
     NumbersAddOps<DerivativeStructure> {
+
+    override val bufferFactory: MutableBufferFactory<DerivativeStructure> = MutableBufferFactory()
+
     public val numberOfVariables: Int = bindings.size
 
     override val zero: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order) }
@@ -77,7 +83,9 @@ public class CmDsField(
 
     override fun scale(a: DerivativeStructure, value: Double): DerivativeStructure = a.multiply(value)
 
-    override fun multiply(left: DerivativeStructure, right: DerivativeStructure): DerivativeStructure = left.multiply(right)
+    override fun multiply(left: DerivativeStructure, right: DerivativeStructure): DerivativeStructure =
+        left.multiply(right)
+
     override fun divide(left: DerivativeStructure, right: DerivativeStructure): DerivativeStructure = left.divide(right)
     override fun sin(arg: DerivativeStructure): DerivativeStructure = arg.sin()
     override fun cos(arg: DerivativeStructure): DerivativeStructure = arg.cos()
@@ -113,8 +121,8 @@ public class CmDsField(
  */
 @Deprecated("Use generic DSAlgebra from the core")
 public object CmDsProcessor : AutoDiffProcessor<Double, DerivativeStructure, CmDsField> {
-     override fun differentiate(
-         function: CmDsField.() -> DerivativeStructure,
+    override fun differentiate(
+        function: CmDsField.() -> DerivativeStructure,
     ): CmDsExpression = CmDsExpression(function)
 }
 
@@ -125,13 +133,16 @@ public object CmDsProcessor : AutoDiffProcessor<Double, DerivativeStructure, CmD
 public class CmDsExpression(
     public val function: CmDsField.() -> DerivativeStructure,
 ) : DifferentiableExpression<Double> {
+
+    override val type: SafeType<Double> get() = DoubleField.type
+
     override operator fun invoke(arguments: Map<Symbol, Double>): Double =
         CmDsField(0, arguments).function().value
 
     /**
      * Get the derivative expression with given orders
      */
-    override fun derivativeOrNull(symbols: List<Symbol>): Expression<Double> = Expression { arguments ->
+    override fun derivativeOrNull(symbols: List<Symbol>): Expression<Double> = Expression(type) { arguments ->
         with(CmDsField(symbols.size, arguments)) { function().derivative(symbols) }
     }
 }
diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt
similarity index 75%
rename from kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt
rename to kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt
index 263463d37..b4680bace 100644
--- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt
+++ b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 package space.kscience.kmath.commons.integration
@@ -13,30 +13,35 @@ import space.kscience.kmath.integration.*
  */
 public class CMGaussRuleIntegrator(
     private val numpoints: Int,
-    private var type: GaussRule = GaussRule.LEGANDRE,
+    private var type: GaussRule = GaussRule.LEGENDRE,
 ) : UnivariateIntegrator<Double> {
 
-    override fun process(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
-        val range = integrand.getFeature<IntegrationRange>()?.range
+    override fun integrate(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
+        val range = integrand[IntegrationRange]
             ?: error("Integration range is not provided")
         val integrator: GaussIntegrator = getIntegrator(range)
         //TODO check performance
         val res: Double = integrator.integrate(integrand.function)
-        return integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + numpoints)
+        return integrand.withAttributes {
+            IntegrandValue(res)
+            IntegrandCallsPerformed(integrand.calls + numpoints)
+        }
     }
 
     private fun getIntegrator(range: ClosedRange<Double>): GaussIntegrator {
         return when (type) {
-            GaussRule.LEGANDRE -> factory.legendre(
+            GaussRule.LEGENDRE -> factory.legendre(
                 numpoints,
                 range.start,
                 range.endInclusive
             )
-            GaussRule.LEGANDREHP -> factory.legendreHighPrecision(
+
+            GaussRule.LEGENDREHP -> factory.legendreHighPrecision(
                 numpoints,
                 range.start,
                 range.endInclusive
             )
+
             GaussRule.UNIFORM -> GaussIntegrator(
                 getUniformRule(
                     range.start,
@@ -65,7 +70,7 @@ public class CMGaussRuleIntegrator(
     }
 
     public enum class GaussRule {
-        UNIFORM, LEGANDRE, LEGANDREHP
+        UNIFORM, LEGENDRE, LEGENDREHP
     }
 
     public companion object {
@@ -74,10 +79,10 @@ public class CMGaussRuleIntegrator(
         public fun integrate(
             range: ClosedRange<Double>,
             numPoints: Int = 100,
-            type: GaussRule = GaussRule.LEGANDRE,
+            type: GaussRule = GaussRule.LEGENDRE,
             function: (Double) -> Double,
-        ): Double = CMGaussRuleIntegrator(numPoints, type).process(
-            UnivariateIntegrand(function, IntegrationRange(range))
+        ): Double = CMGaussRuleIntegrator(numPoints, type).integrate(
+            UnivariateIntegrand({ IntegrationRange(range) }, function)
         ).value
     }
 }
\ No newline at end of file
diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt
similarity index 53%
rename from kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt
rename to kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt
index c3e581d31..83880287e 100644
--- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt
+++ b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,30 +7,32 @@ package space.kscience.kmath.commons.integration
 
 import org.apache.commons.math3.analysis.integration.IterativeLegendreGaussIntegrator
 import org.apache.commons.math3.analysis.integration.SimpsonIntegrator
+import space.kscience.attributes.Attributes
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.integration.*
+import org.apache.commons.math3.analysis.integration.UnivariateIntegrator as CMUnivariateIntegrator
 
 /**
  * Integration wrapper for Common-maths UnivariateIntegrator
  */
 public class CMIntegrator(
     private val defaultMaxCalls: Int = 200,
-    public val integratorBuilder: (Integrand) -> org.apache.commons.math3.analysis.integration.UnivariateIntegrator,
+    public val integratorBuilder: (Integrand<Double>) -> CMUnivariateIntegrator,
 ) : UnivariateIntegrator<Double> {
 
-    override fun process(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
+    override fun integrate(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
         val integrator = integratorBuilder(integrand)
-        val maxCalls = integrand.getFeature<IntegrandMaxCalls>()?.maxCalls ?: defaultMaxCalls
+        val maxCalls = integrand[IntegrandMaxCalls] ?: defaultMaxCalls
         val remainingCalls = maxCalls - integrand.calls
-        val range = integrand.getFeature<IntegrationRange>()?.range
-            ?: error("Integration range is not provided")
+        val range = integrand[IntegrationRange] ?: error("Integration range is not provided")
         val res = integrator.integrate(remainingCalls, integrand.function, range.start, range.endInclusive)
 
-        return integrand +
-                IntegrandValue(res) +
-                IntegrandAbsoluteAccuracy(integrator.absoluteAccuracy) +
-                IntegrandRelativeAccuracy(integrator.relativeAccuracy) +
-                IntegrandCallsPerformed(integrator.evaluations + integrand.calls)
+        return integrand.withAttributes {
+            value(res)
+            IntegrandAbsoluteAccuracy(integrator.absoluteAccuracy)
+            IntegrandRelativeAccuracy(integrator.relativeAccuracy)
+            IntegrandCallsPerformed(integrator.evaluations + integrand.calls)
+        }
     }
 
 
@@ -39,11 +41,9 @@ public class CMIntegrator(
          * Create a Simpson integrator based on [SimpsonIntegrator]
          */
         public fun simpson(defaultMaxCalls: Int = 200): CMIntegrator = CMIntegrator(defaultMaxCalls) { integrand ->
-            val absoluteAccuracy = integrand.getFeature<IntegrandAbsoluteAccuracy>()?.accuracy
-                ?: SimpsonIntegrator.DEFAULT_ABSOLUTE_ACCURACY
-            val relativeAccuracy = integrand.getFeature<IntegrandRelativeAccuracy>()?.accuracy
-                ?: SimpsonIntegrator.DEFAULT_ABSOLUTE_ACCURACY
-            val iterations = integrand.getFeature<IntegrandIterationsRange>()?.range
+            val absoluteAccuracy = integrand[IntegrandAbsoluteAccuracy] ?: SimpsonIntegrator.DEFAULT_ABSOLUTE_ACCURACY
+            val relativeAccuracy = integrand[IntegrandRelativeAccuracy] ?: SimpsonIntegrator.DEFAULT_ABSOLUTE_ACCURACY
+            val iterations = integrand[IntegrandIterationsRange]
                 ?: SimpsonIntegrator.DEFAULT_MIN_ITERATIONS_COUNT..SimpsonIntegrator.SIMPSON_MAX_ITERATIONS_COUNT
 
 
@@ -55,11 +55,11 @@ public class CMIntegrator(
          */
         public fun legandre(numPoints: Int, defaultMaxCalls: Int = numPoints * 5): CMIntegrator =
             CMIntegrator(defaultMaxCalls) { integrand ->
-                val absoluteAccuracy = integrand.getFeature<IntegrandAbsoluteAccuracy>()?.accuracy
+                val absoluteAccuracy = integrand[IntegrandAbsoluteAccuracy]
                     ?: IterativeLegendreGaussIntegrator.DEFAULT_ABSOLUTE_ACCURACY
-                val relativeAccuracy = integrand.getFeature<IntegrandRelativeAccuracy>()?.accuracy
+                val relativeAccuracy = integrand[IntegrandRelativeAccuracy]
                     ?: IterativeLegendreGaussIntegrator.DEFAULT_ABSOLUTE_ACCURACY
-                val iterations = integrand.getFeature<IntegrandIterationsRange>()?.range
+                val iterations = integrand[IntegrandIterationsRange]
                     ?: IterativeLegendreGaussIntegrator.DEFAULT_MIN_ITERATIONS_COUNT..IterativeLegendreGaussIntegrator.DEFAULT_MAX_ITERATIONS_COUNT
 
                 IterativeLegendreGaussIntegrator(
@@ -74,15 +74,9 @@ public class CMIntegrator(
 }
 
 @UnstableKMathAPI
-public var MutableList<IntegrandFeature>.targetAbsoluteAccuracy: Double?
-    get() = filterIsInstance<IntegrandAbsoluteAccuracy>().lastOrNull()?.accuracy
-    set(value) {
-        value?.let { add(IntegrandAbsoluteAccuracy(value)) }
-    }
+public val Attributes.targetAbsoluteAccuracy: Double?
+    get() = get(IntegrandAbsoluteAccuracy)
 
 @UnstableKMathAPI
-public var MutableList<IntegrandFeature>.targetRelativeAccuracy: Double?
-    get() = filterIsInstance<IntegrandRelativeAccuracy>().lastOrNull()?.accuracy
-    set(value) {
-        value?.let { add(IntegrandRelativeAccuracy(value)) }
-    }
\ No newline at end of file
+public val Attributes.targetRelativeAccuracy: Double?
+    get() = get(IntegrandRelativeAccuracy)
diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt
similarity index 55%
rename from kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt
rename to kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt
index d19bd1be0..1fe923cbb 100644
--- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt
+++ b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt
@@ -1,21 +1,29 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.commons.linear
 
 import org.apache.commons.math3.linear.*
+import org.apache.commons.math3.linear.LUDecomposition
+import org.apache.commons.math3.linear.SingularValueDecomposition
+import space.kscience.attributes.SafeType
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.linear.*
-import space.kscience.kmath.nd.StructureFeature
+import space.kscience.kmath.linear.CholeskyDecomposition
+import space.kscience.kmath.linear.QRDecomposition
+import space.kscience.kmath.nd.Structure2D
+import space.kscience.kmath.nd.StructureAttribute
 import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.structures.Buffer
-import space.kscience.kmath.structures.DoubleBuffer
-import kotlin.reflect.KClass
-import kotlin.reflect.cast
+import space.kscience.kmath.structures.Float64
+import space.kscience.kmath.structures.IntBuffer
+import space.kscience.kmath.structures.asBuffer
 
 public class CMMatrix(public val origin: RealMatrix) : Matrix<Double> {
+
     override val rowNum: Int get() = origin.rowDimension
     override val colNum: Int get() = origin.columnDimension
 
@@ -35,15 +43,17 @@ public value class CMVector(public val origin: RealVector) : Point<Double> {
 
 public fun RealVector.toPoint(): CMVector = CMVector(this)
 
-public object CMLinearSpace : LinearSpace<Double, DoubleField> {
-    override val elementAlgebra: DoubleField get() = DoubleField
+public object CMLinearSpace : LinearSpace<Double, Float64Field> {
+    override val elementAlgebra: Float64Field get() = Float64Field
+
+    override val type: SafeType<Double> get() = DoubleField.type
 
     override fun buildMatrix(
         rows: Int,
         columns: Int,
-        initializer: DoubleField.(i: Int, j: Int) -> Double,
+        initializer: Float64Field.(i: Int, j: Int) -> Double,
     ): CMMatrix {
-        val array = Array(rows) { i -> DoubleArray(columns) { j -> DoubleField.initializer(i, j) } }
+        val array = Array(rows) { i -> DoubleArray(columns) { j -> Float64Field.initializer(i, j) } }
         return CMMatrix(Array2DRowRealMatrix(array))
     }
 
@@ -65,8 +75,8 @@ public object CMLinearSpace : LinearSpace<Double, DoubleField> {
     internal fun RealMatrix.wrap(): CMMatrix = CMMatrix(this)
     internal fun RealVector.wrap(): CMVector = CMVector(this)
 
-    override fun buildVector(size: Int, initializer: DoubleField.(Int) -> Double): Point<Double> =
-        ArrayRealVector(DoubleArray(size) { DoubleField.initializer(it) }).wrap()
+    override fun buildVector(size: Int, initializer: Float64Field.(Int) -> Double): Point<Double> =
+        ArrayRealVector(DoubleArray(size) { Float64Field.initializer(it) }).wrap()
 
     override fun Matrix<Double>.plus(other: Matrix<Double>): CMMatrix =
         toCM().origin.add(other.toCM().origin).wrap()
@@ -98,49 +108,48 @@ public object CMLinearSpace : LinearSpace<Double, DoubleField> {
     override fun Double.times(v: Point<Double>): CMVector =
         v * this
 
-    @UnstableKMathAPI
-    override fun <F : StructureFeature> computeFeature(structure: Matrix<Double>, type: KClass<out F>): F? {
-        //Return the feature if it is intrinsic to the structure
-        structure.getFeature(type)?.let { return it }
+    override fun <V, A : StructureAttribute<V>> computeAttribute(structure: Structure2D<Double>, attribute: A): V? {
 
         val origin = structure.toCM().origin
 
-        return when (type) {
-            DiagonalFeature::class -> if (origin is DiagonalMatrix) DiagonalFeature else null
+        val raw: Any? = when (attribute) {
+            IsDiagonal -> if (origin is DiagonalMatrix) Unit else null
+            Determinant -> LUDecomposition(origin).determinant
 
-            DeterminantFeature::class, LupDecompositionFeature::class -> object :
-                DeterminantFeature<Double>,
-                LupDecompositionFeature<Double> {
-                private val lup by lazy { LUDecomposition(origin) }
-                override val determinant: Double by lazy { lup.determinant }
-                override val l: Matrix<Double> by lazy<Matrix<Double>> { CMMatrix(lup.l).withFeature(LFeature) }
-                override val u: Matrix<Double> by lazy<Matrix<Double>> { CMMatrix(lup.u).withFeature(UFeature) }
-                override val p: Matrix<Double> by lazy { CMMatrix(lup.p) }
+            LUP -> object : LupDecomposition<Float64> {
+                val lup by lazy { LUDecomposition(origin) }
+                override val pivot: IntBuffer get() = lup.pivot.asBuffer()
+                override val l: Matrix<Float64> get() = lup.l.wrap()
+                override val u: Matrix<Float64> get() = lup.u.wrap()
             }
 
-            CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<Double> {
-                override val l: Matrix<Double> by lazy<Matrix<Double>> {
-                    val cholesky = CholeskyDecomposition(origin)
-                    CMMatrix(cholesky.l).withFeature(LFeature)
-                }
+            Cholesky -> object : CholeskyDecomposition<Float64> {
+                val cmCholesky by lazy { org.apache.commons.math3.linear.CholeskyDecomposition(origin) }
+                override val l: Matrix<Double> get() = cmCholesky.l.wrap()
             }
 
-            QRDecompositionFeature::class -> object : QRDecompositionFeature<Double> {
-                private val qr by lazy { QRDecomposition(origin) }
-                override val q: Matrix<Double> by lazy<Matrix<Double>> { CMMatrix(qr.q).withFeature(OrthogonalFeature) }
-                override val r: Matrix<Double> by lazy<Matrix<Double>> { CMMatrix(qr.r).withFeature(UFeature) }
+            QR -> object : QRDecomposition<Float64> {
+                val cmQr by lazy { org.apache.commons.math3.linear.QRDecomposition(origin) }
+                override val q: Matrix<Float64> get() = cmQr.q.wrap().withAttribute(OrthogonalAttribute)
+                override val r: Matrix<Float64> get() = cmQr.r.wrap().withAttribute(UpperTriangular)
             }
 
-            SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature<Double> {
-                private val sv by lazy { SingularValueDecomposition(origin) }
-                override val u: Matrix<Double> by lazy { CMMatrix(sv.u) }
-                override val s: Matrix<Double> by lazy { CMMatrix(sv.s) }
-                override val v: Matrix<Double> by lazy { CMMatrix(sv.v) }
-                override val singularValues: Point<Double> by lazy { DoubleBuffer(sv.singularValues) }
+            SVD -> object : space.kscience.kmath.linear.SingularValueDecomposition<Float64> {
+                val cmSvd by lazy { SingularValueDecomposition(origin) }
+
+                override val u: Matrix<Float64> get() = cmSvd.u.wrap()
+                override val s: Matrix<Float64> get() = cmSvd.s.wrap()
+                override val v: Matrix<Float64> get() = cmSvd.v.wrap()
+                override val singularValues: Point<Float64> get() = cmSvd.singularValues.asBuffer()
+
             }
+
             else -> null
-        }?.let(type::cast)
+        }
+        @Suppress("UNCHECKED_CAST")
+        return raw as V?
     }
+
 }
 
 public operator fun CMMatrix.plus(other: CMMatrix): CMMatrix = CMMatrix(origin.add(other.origin))
diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt
similarity index 89%
rename from kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt
rename to kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt
index 19799aab3..0c15d1016 100644
--- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt
+++ b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -48,9 +48,11 @@ public fun CMLinearSpace.inverse(
 
 
 public fun CMLinearSpace.solver(decomposition: CMDecomposition): LinearSolver<Double> = object : LinearSolver<Double> {
-    override fun solve(a: Matrix<Double>, b: Matrix<Double>): Matrix<Double> = solver(a, decomposition).solve(b.toCM().origin).wrap()
+    override fun solve(a: Matrix<Double>, b: Matrix<Double>): Matrix<Double> =
+        solver(a, decomposition).solve(b.toCM().origin).wrap()
 
-    override fun solve(a: Matrix<Double>, b: Point<Double>): Point<Double> = solver(a, decomposition).solve(b.toCM().origin).toPoint()
+    override fun solve(a: Matrix<Double>, b: Point<Double>): Point<Double> =
+        solver(a, decomposition).solve(b.toCM().origin).toPoint()
 
     override fun inverse(matrix: Matrix<Double>): Matrix<Double> = solver(matrix, decomposition).inverse.wrap()
 }
diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt
similarity index 65%
rename from kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt
rename to kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt
index c4dafb6a6..4030e630f 100644
--- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt
+++ b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt
@@ -1,8 +1,9 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 @file:OptIn(UnstableKMathAPI::class)
+
 package space.kscience.kmath.commons.optimization
 
 import org.apache.commons.math3.optim.*
@@ -13,12 +14,13 @@ import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunctionGradient
 import org.apache.commons.math3.optim.nonlinear.scalar.gradient.NonLinearConjugateGradientOptimizer
 import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex
 import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer
+import space.kscience.attributes.AttributesBuilder
+import space.kscience.attributes.SetAttribute
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.expressions.Symbol
 import space.kscience.kmath.expressions.SymbolIndexer
 import space.kscience.kmath.expressions.derivative
 import space.kscience.kmath.expressions.withSymbols
-import space.kscience.kmath.misc.log
 import space.kscience.kmath.optimization.*
 import kotlin.collections.set
 import kotlin.reflect.KClass
@@ -26,34 +28,25 @@ import kotlin.reflect.KClass
 public operator fun PointValuePair.component1(): DoubleArray = point
 public operator fun PointValuePair.component2(): Double = value
 
-public class CMOptimizerEngine(public val optimizerBuilder: () -> MultivariateOptimizer) : OptimizationFeature {
-    override fun toString(): String = "CMOptimizer($optimizerBuilder)"
-}
+public object CMOptimizerEngine : OptimizationAttribute<() -> MultivariateOptimizer>
 
 /**
  * Specify a Commons-maths optimization engine
  */
-public fun FunctionOptimizationBuilder<Double>.cmEngine(optimizerBuilder: () -> MultivariateOptimizer) {
-    addFeature(CMOptimizerEngine(optimizerBuilder))
+public fun AttributesBuilder<FunctionOptimization<Double>>.cmEngine(optimizerBuilder: () -> MultivariateOptimizer) {
+    set(CMOptimizerEngine, optimizerBuilder)
 }
 
-public class CMOptimizerData(public val data: List<SymbolIndexer.() -> OptimizationData>) : OptimizationFeature {
-    public constructor(vararg data: (SymbolIndexer.() -> OptimizationData)) : this(data.toList())
-
-    override fun toString(): String = "CMOptimizerData($data)"
-}
+public object CMOptimizerData : SetAttribute<SymbolIndexer.() -> OptimizationData>
 
 /**
  * Specify Commons-maths optimization data.
  */
-public fun FunctionOptimizationBuilder<Double>.cmOptimizationData(data: SymbolIndexer.() -> OptimizationData) {
-    updateFeature<CMOptimizerData> {
-        val newData = (it?.data ?: emptyList()) + data
-        CMOptimizerData(newData)
-    }
+public fun AttributesBuilder<FunctionOptimization<Double>>.cmOptimizationData(data: SymbolIndexer.() -> OptimizationData) {
+    CMOptimizerData add data
 }
 
-public fun FunctionOptimizationBuilder<Double>.simplexSteps(vararg steps: Pair<Symbol, Double>) {
+public fun AttributesBuilder<FunctionOptimization<Double>>.simplexSteps(vararg steps: Pair<Symbol, Double>) {
     //TODO use convergence checker from features
     cmEngine { SimplexOptimizer(CMOptimizer.defaultConvergenceChecker) }
     cmOptimizationData { NelderMeadSimplex(mapOf(*steps).toDoubleArray()) }
@@ -78,8 +71,8 @@ public object CMOptimizer : Optimizer<Double, FunctionOptimization<Double>> {
     ): FunctionOptimization<Double> {
         val startPoint = problem.startPoint
 
-        val parameters = problem.getFeature<OptimizationParameters>()?.symbols
-            ?: problem.getFeature<OptimizationStartPoint<Double>>()?.point?.keys
+        val parameters = problem.attributes[OptimizationParameters]
+            ?: problem.attributes[OptimizationStartPoint<Double>()]?.keys
             ?: startPoint.keys
 
 
@@ -90,7 +83,7 @@ public object CMOptimizer : Optimizer<Double, FunctionOptimization<Double>> {
                 DEFAULT_MAX_ITER
             )
 
-            val cmOptimizer: MultivariateOptimizer = problem.getFeature<CMOptimizerEngine>()?.optimizerBuilder?.invoke()
+            val cmOptimizer: MultivariateOptimizer = problem.attributes[CMOptimizerEngine]?.invoke()
                 ?: NonLinearConjugateGradientOptimizer(
                     NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES,
                     convergenceChecker
@@ -123,23 +116,26 @@ public object CMOptimizer : Optimizer<Double, FunctionOptimization<Double>> {
             }
             addOptimizationData(gradientFunction)
 
-            val logger = problem.getFeature<OptimizationLog>()
+//            val logger = problem.attributes[OptimizationLog]
 
-            for (feature in problem.features) {
-                when (feature) {
-                    is CMOptimizerData -> feature.data.forEach { dataBuilder ->
-                        addOptimizationData(dataBuilder())
-                    }
-                    is FunctionOptimizationTarget -> when (feature) {
-                        FunctionOptimizationTarget.MAXIMIZE -> addOptimizationData(GoalType.MAXIMIZE)
-                        FunctionOptimizationTarget.MINIMIZE -> addOptimizationData(GoalType.MINIMIZE)
-                    }
-                    else -> logger?.log { "The feature $feature is unused in optimization" }
+            problem.attributes[CMOptimizerData]?.let { builders: Set<SymbolIndexer.() -> OptimizationData> ->
+                builders.forEach { dataBuilder ->
+                    addOptimizationData(dataBuilder())
+                }
+            }
+
+            problem.attributes[FunctionOptimizationTarget]?.let { direction: OptimizationDirection ->
+                when (direction) {
+                    OptimizationDirection.MAXIMIZE -> addOptimizationData(GoalType.MAXIMIZE)
+                    OptimizationDirection.MINIMIZE -> addOptimizationData(GoalType.MINIMIZE)
                 }
             }
 
             val (point, value) = cmOptimizer.optimize(*optimizationData.values.toTypedArray())
-            return problem.withFeatures(OptimizationResult(point.toMap()), OptimizationValue(value))
+            return problem.withAttributes {
+                result(point.toMap())
+                value(value)
+            }
         }
     }
 }
diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt
similarity index 97%
rename from kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt
rename to kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt
index 32962659f..62d31021c 100644
--- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt
+++ b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/transform/Transformations.kt
similarity index 95%
rename from kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt
rename to kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/transform/Transformations.kt
index a77da2d2f..838ab95d5 100644
--- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt
+++ b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/transform/Transformations.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -47,7 +47,7 @@ public object Transformations {
     public fun sine(
         normalization: DstNormalization = DstNormalization.STANDARD_DST_I,
         direction: TransformType = TransformType.FORWARD,
-    ): BufferTransform<Double, Double> = DoubleBufferTransform {
+    ): BufferTransform<Double, Double> = Float64BufferTransform {
         FastSineTransformer(normalization).transform(it.array, direction).asBuffer()
     }
 
@@ -60,7 +60,7 @@ public object Transformations {
 
     public fun hadamard(
         direction: TransformType = TransformType.FORWARD,
-    ): BufferTransform<Double, Double> = DoubleBufferTransform {
+    ): BufferTransform<Double, Double> = Float64BufferTransform {
         FastHadamardTransformer().transform(it.array, direction).asBuffer()
     }
 }
diff --git a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt b/kmath-commons/src/jvmTest/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt
similarity index 97%
rename from kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt
rename to kmath-commons/src/jvmTest/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt
index 7c3c086ed..34905fa7b 100644
--- a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt
+++ b/kmath-commons/src/jvmTest/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt b/kmath-commons/src/jvmTest/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt
similarity index 74%
rename from kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt
rename to kmath-commons/src/jvmTest/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt
index 6541736ce..43857c539 100644
--- a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt
+++ b/kmath-commons/src/jvmTest/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,9 +7,11 @@ package space.kscience.kmath.commons.integration
 
 import org.junit.jupiter.api.Test
 import space.kscience.kmath.UnstableKMathAPI
+import space.kscience.kmath.integration.IntegrandAbsoluteAccuracy
+import space.kscience.kmath.integration.IntegrandRelativeAccuracy
 import space.kscience.kmath.integration.integrate
 import space.kscience.kmath.integration.value
-import space.kscience.kmath.operations.DoubleField.sin
+import space.kscience.kmath.operations.Float64Field.sin
 import kotlin.math.PI
 import kotlin.math.abs
 import kotlin.test.assertTrue
@@ -27,8 +29,8 @@ internal class IntegrationTest {
     @Test
     fun customSimpson() {
         val res = CMIntegrator.simpson().integrate(0.0..PI, {
-            targetRelativeAccuracy = 1e-4
-            targetAbsoluteAccuracy = 1e-4
+            IntegrandRelativeAccuracy(1e-4)
+            IntegrandAbsoluteAccuracy(1e-4)
         }, function).value
         assertTrue { abs(res - 2) < 1e-3 }
         assertTrue { abs(res - 2) > 1e-12 }
diff --git a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt b/kmath-commons/src/jvmTest/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt
similarity index 82%
rename from kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt
rename to kmath-commons/src/jvmTest/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt
index d2e86bb40..8b314cf1a 100644
--- a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt
+++ b/kmath-commons/src/jvmTest/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -13,25 +13,25 @@ import space.kscience.kmath.expressions.Symbol.Companion.x
 import space.kscience.kmath.expressions.Symbol.Companion.y
 import space.kscience.kmath.expressions.autodiff
 import space.kscience.kmath.expressions.symbol
-import space.kscience.kmath.operations.DoubleBufferOps.Companion.map
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64BufferOps.Companion.map
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.optimization.*
 import space.kscience.kmath.random.RandomGenerator
 import space.kscience.kmath.stat.chiSquaredExpression
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import space.kscience.kmath.structures.asBuffer
 import kotlin.test.Test
 
 @OptIn(UnstableKMathAPI::class)
 internal class OptimizeTest {
-    val normal = DSFieldExpression(DoubleField) {
+    val normal = DSFieldExpression(Float64Field) {
         exp(-bindSymbol(x).pow(2) / 2) + exp(-bindSymbol(y).pow(2) / 2)
     }
 
     @Test
     fun testGradientOptimization() = runBlocking {
         val result = normal.optimizeWith(CMOptimizer, x to 1.0, y to 1.0)
-        println(result.resultPoint)
+        println(result.result)
         println(result.resultValue)
     }
 
@@ -42,7 +42,7 @@ internal class OptimizeTest {
             //this sets simplex optimizer
         }
 
-        println(result.resultPoint)
+        println(result.result)
         println(result.resultValue)
     }
 
@@ -61,7 +61,7 @@ internal class OptimizeTest {
             it.pow(2) + it + 1 + chain.next()
         }
 
-        val yErr = DoubleBuffer(x.size) { sigma }
+        val yErr = Float64Buffer(x.size) { sigma }
 
         val chi2 = Double.autodiff.chiSquaredExpression(
             x, y, yErr
@@ -73,8 +73,9 @@ internal class OptimizeTest {
         val result: FunctionOptimization<Double> = chi2.optimizeWith(
             CMOptimizer,
             mapOf(a to 1.5, b to 0.9, c to 1.0),
-            FunctionOptimizationTarget.MINIMIZE
-        )
+        ) {
+            FunctionOptimizationTarget(OptimizationDirection.MINIMIZE)
+        }
         println(result)
         println("Chi2/dof = ${result.resultValue / (x.size - 3)}")
     }
diff --git a/kmath-complex/README.md b/kmath-complex/README.md
index 4e800b7ac..d641452b0 100644
--- a/kmath-complex/README.md
+++ b/kmath-complex/README.md
@@ -8,19 +8,8 @@ Complex and hypercomplex number systems in KMath.
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-complex:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-complex:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-complex:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -29,6 +18,6 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-complex:0.4.0-dev-1")
+    implementation("space.kscience:kmath-complex:0.4.0")
 }
 ```
diff --git a/kmath-complex/build.gradle.kts b/kmath-complex/build.gradle.kts
index 0611e9aae..9ac2d5ab4 100644
--- a/kmath-complex/build.gradle.kts
+++ b/kmath-complex/build.gradle.kts
@@ -6,27 +6,11 @@ kscience {
     jvm()
     js()
     native()
-
-    wasm{
-        browser {
-            testTask {
-                useKarma {
-                    this.webpackConfig.experiments.add("topLevelAwait")
-                    useChromeHeadless()
-                    useConfigDirectory(project.projectDir.resolve("karma.config.d").resolve("wasm"))
-                }
-            }
-        }
-    }
-
-    wasmTest{
-        dependencies {
-            implementation(kotlin("test"))
-        }
-    }
+    wasm()
 
     dependencies {
         api(projects.kmathCore)
+        api(projects.kmathMemory)
     }
 
     testDependencies {
diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt
index b5f1aabe7..89c57527c 100644
--- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt
+++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt
@@ -1,16 +1,18 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.complex
 
+import space.kscience.attributes.SafeType
+import space.kscience.attributes.safeTypeOf
 import space.kscience.kmath.UnstableKMathAPI
-import space.kscience.kmath.memory.MemoryReader
-import space.kscience.kmath.memory.MemorySpec
-import space.kscience.kmath.memory.MemoryWriter
+import space.kscience.kmath.memory.*
 import space.kscience.kmath.operations.*
-import space.kscience.kmath.structures.*
+import space.kscience.kmath.structures.Buffer
+import space.kscience.kmath.structures.MutableBuffer
+import space.kscience.kmath.structures.MutableBufferFactory
 import kotlin.math.*
 
 /**
@@ -51,8 +53,11 @@ public object ComplexField :
     Norm<Complex, Complex>,
     NumbersAddOps<Complex>,
     ScaleOperations<Complex> {
-    override val bufferFactory: MutableBufferFactory<Complex> = MutableBufferFactory { size, init ->
-        MutableMemoryBuffer.create(Complex, size, init)
+    override val bufferFactory: MutableBufferFactory<Complex> = object : MutableBufferFactory<Complex> {
+        override fun invoke(size: Int, builder: (Int) -> Complex): MutableBuffer<Complex> =
+            MutableMemoryBuffer.create(Complex, size, builder)
+
+        override val type: SafeType<Complex> = safeTypeOf()
     }
 
     override val zero: Complex = 0.0.toComplex()
@@ -129,12 +134,31 @@ public object ComplexField :
     }
 
     override fun power(arg: Complex, pow: Number): Complex = if (arg.im == 0.0) {
-        arg.re.pow(pow.toDouble()).toComplex()
+        val powDouble = pow.toDouble()
+        when {
+            arg.re > 0 -> arg.re.pow(powDouble).toComplex()
+            arg.re < 0 -> i * (-arg.re).pow(powDouble)
+            else -> if (powDouble == 0.0) {
+                one
+            } else {
+                zero
+            }
+        }
     } else {
         exp(pow * ln(arg))
     }
 
-    public fun power(arg: Complex, pow: Complex): Complex = exp(pow * ln(arg))
+    public fun power(arg: Complex, pow: Complex): Complex = if (arg == zero || arg == (-0.0).toComplex()) {
+        if (pow == zero) {
+            one
+        } else {
+            zero
+        }
+    } else {
+        exp(pow * ln(arg))
+    }
+
+    public fun Complex.pow(power: Complex): Complex = power(this, power)
 
 
     override fun exp(arg: Complex): Complex = exp(arg.re) * (cos(arg.im) + i * sin(arg.im))
@@ -189,6 +213,7 @@ public object ComplexField :
     override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg)
 }
 
+
 /**
  * Represents `double`-based complex number.
  *
@@ -202,8 +227,10 @@ public data class Complex(val re: Double, val im: Double) {
     override fun toString(): String = "($re + i * $im)"
 
     public companion object : MemorySpec<Complex> {
-        override val objectSize: Int
-            get() = 16
+
+        override val type: SafeType<Complex> get() = safeTypeOf()
+
+        override val objectSize: Int get() = 16
 
         override fun MemoryReader.read(offset: Int): Complex =
             Complex(readDouble(offset), readDouble(offset + 8))
diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt
index 90a6b3253..3fce2c882 100644
--- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt
+++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -19,7 +19,8 @@ import kotlin.contracts.contract
  */
 @OptIn(UnstableKMathAPI::class)
 public sealed class ComplexFieldOpsND : BufferedFieldOpsND<Complex, ComplexField>(ComplexField.bufferAlgebra),
-    ScaleOperations<StructureND<Complex>>, ExtendedFieldOps<StructureND<Complex>>, PowerOperations<StructureND<Complex>> {
+    ScaleOperations<StructureND<Complex>>, ExtendedFieldOps<StructureND<Complex>>,
+    PowerOperations<StructureND<Complex>> {
 
     @OptIn(PerformancePitfall::class)
     override fun StructureND<Complex>.toBufferND(): BufferND<Complex> = when (this) {
@@ -53,7 +54,7 @@ public sealed class ComplexFieldOpsND : BufferedFieldOpsND<Complex, ComplexField
     override fun atanh(arg: StructureND<Complex>): BufferND<Complex> = mapInline(arg.toBufferND()) { atanh(it) }
 
     override fun power(arg: StructureND<Complex>, pow: Number): StructureND<Complex> =
-        mapInline(arg.toBufferND()) { power(it,pow) }
+        mapInline(arg.toBufferND()) { power(it, pow) }
 
     public companion object : ComplexFieldOpsND()
 }
diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt
index d4259c4dc..6a6171975 100644
--- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt
+++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt
@@ -1,19 +1,18 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.complex
 
+import space.kscience.attributes.SafeType
+import space.kscience.attributes.safeTypeOf
 import space.kscience.kmath.UnstableKMathAPI
-import space.kscience.kmath.memory.MemoryReader
-import space.kscience.kmath.memory.MemorySpec
-import space.kscience.kmath.memory.MemoryWriter
+import space.kscience.kmath.memory.*
 import space.kscience.kmath.operations.*
 import space.kscience.kmath.structures.Buffer
-import space.kscience.kmath.structures.MemoryBuffer
 import space.kscience.kmath.structures.MutableBuffer
-import space.kscience.kmath.structures.MutableMemoryBuffer
+import space.kscience.kmath.structures.MutableBufferFactory
 import kotlin.math.*
 
 /**
@@ -78,6 +77,7 @@ public class Quaternion(
 
     public companion object : MemorySpec<Quaternion> {
         override val objectSize: Int get() = 32
+        override val type: SafeType<Quaternion> get() = safeTypeOf()
 
         override fun MemoryReader.read(offset: Int): Quaternion = Quaternion(
             readDouble(offset),
@@ -122,16 +122,19 @@ public val Quaternion.reciprocal: Quaternion
 /**
  * Produce a normalized version of this quaternion
  */
-public fun Quaternion.normalized(): Quaternion = with(QuaternionField){ this@normalized / norm(this@normalized) }
+public fun Quaternion.normalized(): Quaternion = with(QuaternionAlgebra) { this@normalized / norm(this@normalized) }
 
 /**
  * A field of [Quaternion].
  */
 @OptIn(UnstableKMathAPI::class)
-public object QuaternionField : Field<Quaternion>, Norm<Quaternion, Double>, PowerOperations<Quaternion>,
+public object QuaternionAlgebra : Group<Quaternion>, Norm<Quaternion, Double>, PowerOperations<Quaternion>,
     ExponentialOperations<Quaternion>, NumbersAddOps<Quaternion>, ScaleOperations<Quaternion> {
+
+    override val bufferFactory: MutableBufferFactory<Quaternion> = MutableBufferFactory()
+
     override val zero: Quaternion = Quaternion(0.0)
-    override val one: Quaternion = Quaternion(1.0)
+    public val one: Quaternion = Quaternion(1.0)
 
     /**
      * The `i` quaternion unit.
@@ -154,14 +157,16 @@ public object QuaternionField : Field<Quaternion>, Norm<Quaternion, Double>, Pow
     override fun scale(a: Quaternion, value: Double): Quaternion =
         Quaternion(a.w * value, a.x * value, a.y * value, a.z * value)
 
-    override fun multiply(left: Quaternion, right: Quaternion): Quaternion = Quaternion(
+    public fun multiply(left: Quaternion, right: Quaternion): Quaternion = Quaternion(
         left.w * right.w - left.x * right.x - left.y * right.y - left.z * right.z,
         left.w * right.x + left.x * right.w + left.y * right.z - left.z * right.y,
         left.w * right.y - left.x * right.z + left.y * right.w + left.z * right.x,
         left.w * right.z + left.x * right.y - left.y * right.x + left.z * right.w,
     )
 
-    override fun divide(left: Quaternion, right: Quaternion): Quaternion {
+    public operator fun Quaternion.times(other: Quaternion): Quaternion = multiply(this, other)
+
+    public fun divide(left: Quaternion, right: Quaternion): Quaternion {
         val s = right.w * right.w + right.x * right.x + right.y * right.y + right.z * right.z
 
         return Quaternion(
@@ -172,14 +177,17 @@ public object QuaternionField : Field<Quaternion>, Norm<Quaternion, Double>, Pow
         )
     }
 
+    public operator fun Quaternion.div(other: Quaternion): Quaternion = divide(this, other)
+
+
     override fun power(arg: Quaternion, pow: Number): Quaternion {
-        if (pow is Int) return pwr(arg, pow)
-        if (floor(pow.toDouble()) == pow.toDouble()) return pwr(arg, pow.toInt())
+        if (pow is Int) return power(arg, pow)
+        if (floor(pow.toDouble()) == pow.toDouble()) return power(arg, pow.toInt())
         return exp(pow * ln(arg))
     }
 
-    private fun pwr(x: Quaternion, a: Int): Quaternion = when {
-        a < 0 -> -(pwr(x, -a))
+    private fun power(x: Quaternion, a: Int): Quaternion = when {
+        a < 0 -> -(power(x, -a))
         a == 0 -> one
         a == 1 -> x
         a == 2 -> pwr2(x)
@@ -243,14 +251,15 @@ public object QuaternionField : Field<Quaternion>, Norm<Quaternion, Double>, Pow
         return Quaternion(ln(n), th * arg.x, th * arg.y, th * arg.z)
     }
 
-    override operator fun Number.plus(other: Quaternion): Quaternion =
+    public override operator fun Number.plus(other: Quaternion): Quaternion =
         Quaternion(toDouble() + other.w, other.x, other.y, other.z)
 
-    override operator fun Number.minus(other: Quaternion): Quaternion =
+    public override operator fun Number.minus(other: Quaternion): Quaternion =
         Quaternion(toDouble() - other.w, -other.x, -other.y, -other.z)
 
-    override operator fun Quaternion.plus(other: Number): Quaternion = Quaternion(w + other.toDouble(), x, y, z)
-    override operator fun Quaternion.minus(other: Number): Quaternion = Quaternion(w - other.toDouble(), x, y, z)
+    public override operator fun Quaternion.plus(other: Number): Quaternion = Quaternion(w + other.toDouble(), x, y, z)
+
+    public override operator fun Quaternion.minus(other: Number): Quaternion = Quaternion(w - other.toDouble(), x, y, z)
 
     override operator fun Number.times(arg: Quaternion): Quaternion =
         Quaternion(toDouble() * arg.w, toDouble() * arg.x, toDouble() * arg.y, toDouble() * arg.z)
@@ -275,7 +284,7 @@ public object QuaternionField : Field<Quaternion>, Norm<Quaternion, Double>, Pow
     override fun sinh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / 2.0
     override fun cosh(arg: Quaternion): Quaternion = (exp(arg) + exp(-arg)) / 2.0
     override fun tanh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg))
-    override fun asinh(arg: Quaternion): Quaternion = ln(sqrt(arg * arg + one) + arg)
+    override fun asinh(arg: Quaternion): Quaternion = ln(sqrt(pwr2(arg) + one) + arg)
     override fun acosh(arg: Quaternion): Quaternion = ln(arg + sqrt((arg - one) * (arg + one)))
     override fun atanh(arg: Quaternion): Quaternion = (ln(arg + one) - ln(one - arg)) / 2.0
 }
diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt
index ca3f8f43f..124703cbe 100644
--- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt
+++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt
index e11f1c1ea..06f7f4580 100644
--- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt
+++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -58,24 +58,30 @@ internal class ComplexFieldTest {
     }
 
     @Test
-    fun testInverseHyperbolicSine() {
-        assertEquals(
-            ComplexField { i * PI.toComplex() / 2 },
-            ComplexField { asinh(i) })
+    fun testInverseHyperbolicSine() = ComplexField {
+        assertEquals(i * PI.toComplex() / 2, asinh(i))
     }
 
     @Test
-    fun testPower() {
-        assertEquals(ComplexField.zero, ComplexField { zero pow 2 })
-        assertEquals(ComplexField.zero, ComplexField { zero pow 2 })
+    fun testPower() = ComplexField {
+        assertEquals(zero, zero pow 2)
+        assertEquals(zero, zero pow 2)
 
         assertEquals(
-            ComplexField { i * 8 }.let { it.im.toInt() to it.re.toInt() },
-            ComplexField { Complex(2, 2) pow 2 }.let { it.im.toInt() to it.re.toInt() })
+            (i * 8).let { it.im.toInt() to it.re.toInt() },
+            (Complex(2, 2) pow 2).let { it.im.toInt() to it.re.toInt() })
+
+        assertEquals(1.0, Complex(0.0).pow(Complex(0.0)).re, 0.01)
+        assertEquals(1.0, Complex(-0.0).pow(Complex(0.0)).re, 0.01)
+        assertEquals(0.0, Complex(0.0).pow(Complex(2.0)).re, 0.01)
+        assertEquals(0.0, Complex(-0.0).pow(Complex(2.0)).re, 0.01)
+        assertEquals(1.0, Complex(-1.0).pow(Complex(2.0)).re, 0.01)
+        assertEquals(2.0, power(Complex(-4.0, 0.0), 0.5 + 0 * i).im, 0.01)
+        assertEquals(2.0, power(Complex(-4.0, 0.0), 0.5).im, 0.01)
     }
 
     @Test
-    fun testNorm() {
-        assertEquals(2.toComplex(), ComplexField { norm(2 * i) })
+    fun testNorm() = ComplexField {
+        assertEquals(2.toComplex(), norm(2 * i))
     }
 }
diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt
index 1a35d1dd8..a736d5ac5 100644
--- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt
+++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt
index 767406e0b..9b7bdfa95 100644
--- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt
+++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionTest.kt
index fd0fd46a7..b60b853de 100644
--- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionTest.kt
+++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -14,20 +14,20 @@ internal class QuaternionTest {
 
     @Test
     fun testNorm() {
-        assertEquals(2.0, QuaternionField.norm(Quaternion(1.0, 1.0, 1.0, 1.0)))
+        assertEquals(2.0, QuaternionAlgebra.norm(Quaternion(1.0, 1.0, 1.0, 1.0)))
     }
 
     @Test
-    fun testInverse() = QuaternionField {
+    fun testInverse() = QuaternionAlgebra {
         val q = Quaternion(1.0, 2.0, -3.0, 4.0)
         assertBufferEquals(one, q * q.reciprocal, 1e-4)
     }
 
     @Test
     fun testAddition() {
-        assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(16, 16) + Quaternion(26, 26) })
-        assertEquals(Quaternion(42, 16), QuaternionField { Quaternion(16, 16) + 26 })
-        assertEquals(Quaternion(42, 16), QuaternionField { 26 + Quaternion(16, 16) })
+        assertEquals(Quaternion(42, 42), QuaternionAlgebra { Quaternion(16, 16) + Quaternion(26, 26) })
+        assertEquals(Quaternion(42, 16), QuaternionAlgebra { Quaternion(16, 16) + 26 })
+        assertEquals(Quaternion(42, 16), QuaternionAlgebra { 26 + Quaternion(16, 16) })
     }
 
 //    @Test
@@ -39,9 +39,9 @@ internal class QuaternionTest {
 
     @Test
     fun testMultiplication() {
-        assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(4.2, 0) * Quaternion(10, 10) })
-        assertEquals(Quaternion(42, 21), QuaternionField { Quaternion(4.2, 2.1) * 10 })
-        assertEquals(Quaternion(42, 21), QuaternionField { 10 * Quaternion(4.2, 2.1) })
+        assertEquals(Quaternion(42, 42), QuaternionAlgebra { Quaternion(4.2, 0) * Quaternion(10, 10) })
+        assertEquals(Quaternion(42, 21), QuaternionAlgebra { Quaternion(4.2, 2.1) * 10 })
+        assertEquals(Quaternion(42, 21), QuaternionAlgebra { 10 * Quaternion(4.2, 2.1) })
     }
 
 //    @Test
@@ -53,11 +53,11 @@ internal class QuaternionTest {
 
     @Test
     fun testPower() {
-        assertEquals(QuaternionField.zero, QuaternionField { zero pow 2 })
-        assertEquals(QuaternionField.zero, QuaternionField { zero pow 2 })
+        assertEquals(QuaternionAlgebra.zero, QuaternionAlgebra { zero pow 2 })
+        assertEquals(QuaternionAlgebra.zero, QuaternionAlgebra { zero pow 2 })
 
         assertEquals(
-            QuaternionField { i * 8 }.let { it.x.toInt() to it.w.toInt() },
-            QuaternionField { Quaternion(2, 2) pow 2 }.let { it.x.toInt() to it.w.toInt() })
+            QuaternionAlgebra { i * 8 }.let { it.x.toInt() to it.w.toInt() },
+            QuaternionAlgebra { Quaternion(2, 2) pow 2 }.let { it.x.toInt() to it.w.toInt() })
     }
 }
diff --git a/kmath-core/README.md b/kmath-core/README.md
index b58105d2f..acb90a411 100644
--- a/kmath-core/README.md
+++ b/kmath-core/README.md
@@ -11,23 +11,13 @@ objects to the expression by providing a context. Expressions can be used for a
 performance calculations to code generation.
  - [domains](src/commonMain/kotlin/space/kscience/kmath/domains) : Domains
  - [autodiff](src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
+ - [Parallel linear algebra](#) : Parallel implementation for `LinearAlgebra`
 
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-core:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-core:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-core:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -36,6 +26,6 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-core:0.4.0-dev-1")
+    implementation("space.kscience:kmath-core:0.4.0")
 }
 ```
diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api
index 42d8277bd..460c2e3c4 100644
--- a/kmath-core/api/kmath-core.api
+++ b/kmath-core/api/kmath-core.api
@@ -1,3 +1,14 @@
+public abstract interface annotation class space/kscience/kmath/PerformancePitfall : java/lang/annotation/Annotation {
+	public abstract fun message ()Ljava/lang/String;
+}
+
+public abstract interface annotation class space/kscience/kmath/UnsafeKMathAPI : java/lang/annotation/Annotation {
+	public abstract fun message ()Ljava/lang/String;
+}
+
+public abstract interface annotation class space/kscience/kmath/UnstableKMathAPI : java/lang/annotation/Annotation {
+}
+
 public final class space/kscience/kmath/data/ColumnarDataKt {
 }
 
@@ -41,17 +52,19 @@ public final class space/kscience/kmath/expressions/DSCompiler {
 	public final fun getSizes ()[[I
 }
 
-public final class space/kscience/kmath/expressions/DerivationResult {
-	public fun <init> (Ljava/lang/Object;Ljava/util/Map;Lspace/kscience/kmath/operations/Field;)V
+public final class space/kscience/kmath/expressions/DerivationResult : space/kscience/attributes/WithType {
+	public synthetic fun <init> (Ljava/lang/Object;Lkotlin/reflect/KType;Ljava/util/Map;Lspace/kscience/kmath/operations/Field;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
 	public final fun derivative (Lspace/kscience/kmath/expressions/Symbol;)Ljava/lang/Object;
 	public final fun div ()Ljava/lang/Object;
 	public final fun getContext ()Lspace/kscience/kmath/operations/Field;
+	public fun getType-V0oMfBY ()Lkotlin/reflect/KType;
 	public final fun getValue ()Ljava/lang/Object;
 }
 
 public final class space/kscience/kmath/expressions/DiffExpressionWithDefault : space/kscience/kmath/expressions/DifferentiableExpression {
 	public fun <init> (Lspace/kscience/kmath/expressions/DifferentiableExpression;Ljava/util/Map;)V
 	public fun derivativeOrNull (Ljava/util/List;)Lspace/kscience/kmath/expressions/Expression;
+	public fun getType-V0oMfBY ()Lkotlin/reflect/KType;
 	public fun invoke (Ljava/util/Map;)Ljava/lang/Object;
 }
 
@@ -71,7 +84,7 @@ public final class space/kscience/kmath/expressions/DifferentiableExpressionKt {
 public final class space/kscience/kmath/expressions/DoubleExpression$Companion {
 }
 
-public abstract interface class space/kscience/kmath/expressions/Expression {
+public abstract interface class space/kscience/kmath/expressions/Expression : space/kscience/attributes/WithType {
 	public abstract fun invoke (Ljava/util/Map;)Ljava/lang/Object;
 }
 
@@ -80,6 +93,7 @@ public abstract interface class space/kscience/kmath/expressions/ExpressionAlgeb
 }
 
 public final class space/kscience/kmath/expressions/ExpressionKt {
+	public static final fun Expression-AckJDF4 (Lkotlin/reflect/KType;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/Expression;
 	public static final fun callByString (Lspace/kscience/kmath/expressions/Expression;[Lkotlin/Pair;)Ljava/lang/Object;
 	public static final fun callBySymbol (Lspace/kscience/kmath/expressions/Expression;[Lkotlin/Pair;)Ljava/lang/Object;
 	public static final fun getBinding (Lspace/kscience/kmath/expressions/ExpressionAlgebra;)Lkotlin/properties/ReadOnlyProperty;
@@ -88,6 +102,7 @@ public final class space/kscience/kmath/expressions/ExpressionKt {
 
 public final class space/kscience/kmath/expressions/ExpressionWithDefault : space/kscience/kmath/expressions/Expression {
 	public fun <init> (Lspace/kscience/kmath/expressions/Expression;Ljava/util/Map;)V
+	public fun getType-V0oMfBY ()Lkotlin/reflect/KType;
 	public fun invoke (Ljava/util/Map;)Ljava/lang/Object;
 }
 
@@ -110,11 +125,12 @@ public abstract class space/kscience/kmath/expressions/FunctionalExpressionAlgeb
 	public synthetic fun const (Ljava/lang/Object;)Ljava/lang/Object;
 	public fun const (Ljava/lang/Object;)Lspace/kscience/kmath/expressions/Expression;
 	public final fun getAlgebra ()Lspace/kscience/kmath/operations/Algebra;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
 	public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1;
 }
 
 public final class space/kscience/kmath/expressions/FunctionalExpressionAlgebraKt {
-	public static final fun expression (Lspace/kscience/kmath/operations/DoubleField;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/Expression;
+	public static final fun expression (Lspace/kscience/kmath/operations/Float64Field;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/Expression;
 	public static final fun expressionInExtendedField (Lspace/kscience/kmath/operations/ExtendedField;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/Expression;
 	public static final fun expressionInField (Lspace/kscience/kmath/operations/Field;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/Expression;
 	public static final fun expressionInGroup (Lspace/kscience/kmath/operations/Group;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/Expression;
@@ -270,6 +286,7 @@ public final class space/kscience/kmath/expressions/MstExtendedField : space/ksc
 	public fun divide (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Binary;
 	public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object;
 	public fun exp (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
 	public synthetic fun getOne ()Ljava/lang/Object;
 	public fun getOne ()Lspace/kscience/kmath/expressions/MST$Numeric;
 	public synthetic fun getZero ()Ljava/lang/Object;
@@ -312,6 +329,7 @@ public final class space/kscience/kmath/expressions/MstField : space/kscience/km
 	public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Symbol;
 	public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
 	public fun divide (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Binary;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
 	public synthetic fun getOne ()Ljava/lang/Object;
 	public fun getOne ()Lspace/kscience/kmath/expressions/MST$Numeric;
 	public synthetic fun getZero ()Ljava/lang/Object;
@@ -338,6 +356,7 @@ public final class space/kscience/kmath/expressions/MstGroup : space/kscience/km
 	public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2;
 	public synthetic fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object;
 	public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Symbol;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
 	public synthetic fun getZero ()Ljava/lang/Object;
 	public fun getZero ()Lspace/kscience/kmath/expressions/MST$Numeric;
 	public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
@@ -360,6 +379,7 @@ public final class space/kscience/kmath/expressions/MstNumericAlgebra : space/ks
 	public fun bindSymbol (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Symbol;
 	public synthetic fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object;
 	public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Symbol;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
 	public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
 	public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/expressions/MST$Numeric;
 	public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1;
@@ -372,6 +392,7 @@ public final class space/kscience/kmath/expressions/MstRing : space/kscience/kma
 	public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2;
 	public synthetic fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object;
 	public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Symbol;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
 	public synthetic fun getOne ()Ljava/lang/Object;
 	public fun getOne ()Lspace/kscience/kmath/expressions/MST$Numeric;
 	public synthetic fun getZero ()Ljava/lang/Object;
@@ -398,11 +419,10 @@ public final class space/kscience/kmath/expressions/NamedMatrix : space/kscience
 	public fun get (II)Ljava/lang/Object;
 	public final fun get (Lspace/kscience/kmath/expressions/Symbol;Lspace/kscience/kmath/expressions/Symbol;)Ljava/lang/Object;
 	public fun get ([I)Ljava/lang/Object;
+	public fun getAttributes ()Lspace/kscience/attributes/Attributes;
 	public fun getColNum ()I
 	public fun getColumns ()Ljava/util/List;
 	public fun getDimension ()I
-	public synthetic fun getFeature (Lkotlin/reflect/KClass;)Ljava/lang/Object;
-	public fun getFeature (Lkotlin/reflect/KClass;)Lspace/kscience/kmath/nd/StructureFeature;
 	public final fun getIndexer ()Lspace/kscience/kmath/expressions/SymbolIndexer;
 	public fun getIndices ()Lspace/kscience/kmath/nd/ShapeIndexer;
 	public fun getRowNum ()I
@@ -425,6 +445,7 @@ public final class space/kscience/kmath/expressions/SimpleAutoDiffExpression : s
 	public fun derivativeOrNull (Lspace/kscience/kmath/expressions/Symbol;)Lspace/kscience/kmath/expressions/Expression;
 	public final fun getField ()Lspace/kscience/kmath/operations/Field;
 	public final fun getFunction ()Lkotlin/jvm/functions/Function1;
+	public fun getType-V0oMfBY ()Lkotlin/reflect/KType;
 	public fun invoke (Ljava/util/Map;)Ljava/lang/Object;
 }
 
@@ -481,7 +502,8 @@ public class space/kscience/kmath/expressions/SimpleAutoDiffField : space/kscien
 	public final fun derive (Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
 	public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
 	public fun divide (Lspace/kscience/kmath/expressions/AutoDiffValue;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue;
-	public final fun getContext ()Lspace/kscience/kmath/operations/Field;
+	public final fun getAlgebra ()Lspace/kscience/kmath/operations/Field;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
 	public final fun getD (Lspace/kscience/kmath/expressions/AutoDiffValue;)Ljava/lang/Object;
 	public synthetic fun getOne ()Ljava/lang/Object;
 	public fun getOne ()Lspace/kscience/kmath/expressions/AutoDiffValue;
@@ -572,62 +594,117 @@ public final class space/kscience/kmath/linear/BufferedLinearSpaceKt {
 	public static final fun getLinearSpace (Lspace/kscience/kmath/operations/Ring;)Lspace/kscience/kmath/linear/BufferedLinearSpace;
 }
 
-public abstract interface class space/kscience/kmath/linear/CholeskyDecompositionFeature : space/kscience/kmath/linear/MatrixFeature {
+public abstract interface class space/kscience/kmath/linear/CholeskyDecomposition {
 	public abstract fun getL ()Lspace/kscience/kmath/nd/Structure2D;
 }
 
-public abstract interface class space/kscience/kmath/linear/DeterminantFeature : space/kscience/kmath/linear/MatrixFeature {
-	public abstract fun getDeterminant ()Ljava/lang/Object;
+public final class space/kscience/kmath/linear/CholeskyDecompositionAttribute : space/kscience/attributes/PolymorphicAttribute, space/kscience/kmath/linear/MatrixAttribute {
+	public fun <init> ()V
 }
 
-public abstract interface class space/kscience/kmath/linear/DiagonalFeature : space/kscience/kmath/linear/MatrixFeature {
-	public static final field Companion Lspace/kscience/kmath/linear/DiagonalFeature$Companion;
+public final class space/kscience/kmath/linear/Determinant : space/kscience/attributes/PolymorphicAttribute, space/kscience/kmath/linear/MatrixAttribute {
+	public synthetic fun <init> (Lkotlin/reflect/KType;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
 }
 
-public final class space/kscience/kmath/linear/DiagonalFeature$Companion : space/kscience/kmath/linear/DiagonalFeature {
-}
-
-public final class space/kscience/kmath/linear/DoubleLinearSpace : space/kscience/kmath/linear/LinearSpace {
-	public static final field INSTANCE Lspace/kscience/kmath/linear/DoubleLinearSpace;
+public final class space/kscience/kmath/linear/Float64LinearSpace : space/kscience/kmath/linear/LinearSpace {
+	public static final field INSTANCE Lspace/kscience/kmath/linear/Float64LinearSpace;
 	public fun buildMatrix (IILkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/Structure2D;
 	public synthetic fun buildVector (ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/structures/Buffer;
-	public fun buildVector-CZ9oacQ (ILkotlin/jvm/functions/Function2;)[D
-	public final fun div-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;D)[D
+	public fun buildVector-Vq5tpWc (ILkotlin/jvm/functions/Function2;)[D
+	public final fun div-Vq5tpWc (Lspace/kscience/kmath/structures/Buffer;D)[D
 	public fun dot (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D;
 	public synthetic fun dot (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
-	public fun dot-CZ9oacQ (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/structures/Buffer;)[D
-	public fun getElementAlgebra ()Lspace/kscience/kmath/operations/DoubleField;
+	public fun dot-Vq5tpWc (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/structures/Buffer;)[D
+	public fun getElementAlgebra ()Lspace/kscience/kmath/operations/Float64Field;
 	public synthetic fun getElementAlgebra ()Lspace/kscience/kmath/operations/Ring;
 	public fun minus (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D;
 	public synthetic fun minus (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
-	public fun minus-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D
+	public fun minus-Vq5tpWc (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D
 	public fun plus (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D;
 	public synthetic fun plus (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
-	public fun plus-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D
+	public fun plus-Vq5tpWc (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D
 	public synthetic fun times (Ljava/lang/Object;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
 	public fun times (Lspace/kscience/kmath/nd/Structure2D;D)Lspace/kscience/kmath/nd/Structure2D;
 	public synthetic fun times (Lspace/kscience/kmath/nd/Structure2D;Ljava/lang/Object;)Lspace/kscience/kmath/nd/Structure2D;
 	public synthetic fun times (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Object;)Lspace/kscience/kmath/structures/Buffer;
-	public fun times-CZ9oacQ (DLspace/kscience/kmath/structures/Buffer;)[D
-	public fun times-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;D)[D
+	public fun times-Vq5tpWc (DLspace/kscience/kmath/structures/Buffer;)[D
+	public fun times-Vq5tpWc (Lspace/kscience/kmath/structures/Buffer;D)[D
 	public fun unaryMinus (Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D;
 }
 
-public final class space/kscience/kmath/linear/DoubleLinearSpaceKt {
-	public static final fun getLinearSpace (Lspace/kscience/kmath/operations/DoubleField;)Lspace/kscience/kmath/linear/DoubleLinearSpace;
+public final class space/kscience/kmath/linear/Float64LinearSpaceKt {
+	public static final fun getLinearSpace (Lspace/kscience/kmath/operations/Float64Field;)Lspace/kscience/kmath/linear/Float64LinearSpace;
 }
 
-public abstract interface class space/kscience/kmath/linear/InverseMatrixFeature : space/kscience/kmath/linear/MatrixFeature {
-	public abstract fun getInverse ()Lspace/kscience/kmath/nd/Structure2D;
+public final class space/kscience/kmath/linear/Float64ParallelLinearSpace : space/kscience/kmath/linear/LinearSpace {
+	public static final field INSTANCE Lspace/kscience/kmath/linear/Float64ParallelLinearSpace;
+	public fun buildMatrix (IILkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/Structure2D;
+	public synthetic fun buildVector (ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/structures/Buffer;
+	public fun buildVector-Vq5tpWc (ILkotlin/jvm/functions/Function2;)[D
+	public final fun div-Vq5tpWc (Lspace/kscience/kmath/structures/Buffer;D)[D
+	public fun dot (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D;
+	public synthetic fun dot (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
+	public fun dot-Vq5tpWc (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/structures/Buffer;)[D
+	public fun getElementAlgebra ()Lspace/kscience/kmath/operations/Float64Field;
+	public synthetic fun getElementAlgebra ()Lspace/kscience/kmath/operations/Ring;
+	public fun minus (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D;
+	public synthetic fun minus (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
+	public fun minus-Vq5tpWc (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D
+	public fun plus (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D;
+	public synthetic fun plus (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
+	public fun plus-Vq5tpWc (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun times (Ljava/lang/Object;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
+	public fun times (Lspace/kscience/kmath/nd/Structure2D;D)Lspace/kscience/kmath/nd/Structure2D;
+	public synthetic fun times (Lspace/kscience/kmath/nd/Structure2D;Ljava/lang/Object;)Lspace/kscience/kmath/nd/Structure2D;
+	public synthetic fun times (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Object;)Lspace/kscience/kmath/structures/Buffer;
+	public fun times-Vq5tpWc (DLspace/kscience/kmath/structures/Buffer;)[D
+	public fun times-Vq5tpWc (Lspace/kscience/kmath/structures/Buffer;D)[D
+	public fun unaryMinus (Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D;
 }
 
-public final class space/kscience/kmath/linear/LFeature : space/kscience/kmath/linear/MatrixFeature {
-	public static final field INSTANCE Lspace/kscience/kmath/linear/LFeature;
+public final class space/kscience/kmath/linear/Float64ParallelLinearSpaceKt {
+	public static final fun getParallel (Lspace/kscience/kmath/linear/Float64LinearSpace;)Lspace/kscience/kmath/linear/Float64ParallelLinearSpace;
 }
 
-public abstract interface class space/kscience/kmath/linear/LUDecompositionFeature : space/kscience/kmath/linear/MatrixFeature {
-	public abstract fun getL ()Lspace/kscience/kmath/nd/Structure2D;
-	public abstract fun getU ()Lspace/kscience/kmath/nd/Structure2D;
+public final class space/kscience/kmath/linear/GenericLupDecomposition : space/kscience/kmath/linear/LupDecomposition {
+	public synthetic fun <init> (Lspace/kscience/kmath/operations/Field;Lspace/kscience/kmath/nd/Structure2D;[IZLkotlin/jvm/internal/DefaultConstructorMarker;)V
+	public final fun getDeterminant ()Ljava/lang/Object;
+	public final fun getElementAlgebra ()Lspace/kscience/kmath/operations/Field;
+	public fun getL ()Lspace/kscience/kmath/nd/Structure2D;
+	public fun getPivot-M_oXE9g ()[I
+	public fun getU ()Lspace/kscience/kmath/nd/Structure2D;
+}
+
+public final class space/kscience/kmath/linear/Inverted : space/kscience/attributes/PolymorphicAttribute, space/kscience/kmath/linear/MatrixAttribute {
+	public fun <init> ()V
+}
+
+public abstract interface class space/kscience/kmath/linear/IsDiagonal : space/kscience/attributes/FlagAttribute, space/kscience/kmath/linear/MatrixAttribute {
+	public static final field Companion Lspace/kscience/kmath/linear/IsDiagonal$Companion;
+}
+
+public final class space/kscience/kmath/linear/IsDiagonal$Companion : space/kscience/kmath/linear/IsDiagonal {
+}
+
+public final class space/kscience/kmath/linear/IsUnit : space/kscience/kmath/linear/IsDiagonal {
+	public static final field INSTANCE Lspace/kscience/kmath/linear/IsUnit;
+}
+
+public final class space/kscience/kmath/linear/IsZero : space/kscience/kmath/linear/IsDiagonal {
+	public static final field INSTANCE Lspace/kscience/kmath/linear/IsZero;
+}
+
+public final class space/kscience/kmath/linear/LUDecomposition {
+	public fun <init> (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)V
+	public final fun component1 ()Lspace/kscience/kmath/nd/Structure2D;
+	public final fun component2 ()Lspace/kscience/kmath/nd/Structure2D;
+	public final fun copy (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/linear/LUDecomposition;
+	public static synthetic fun copy$default (Lspace/kscience/kmath/linear/LUDecomposition;Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;ILjava/lang/Object;)Lspace/kscience/kmath/linear/LUDecomposition;
+	public fun equals (Ljava/lang/Object;)Z
+	public final fun getL ()Lspace/kscience/kmath/nd/Structure2D;
+	public final fun getU ()Lspace/kscience/kmath/nd/Structure2D;
+	public fun hashCode ()I
+	public fun toString ()Ljava/lang/String;
 }
 
 public abstract interface class space/kscience/kmath/linear/LinearSolver {
@@ -636,13 +713,15 @@ public abstract interface class space/kscience/kmath/linear/LinearSolver {
 	public fun solve (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
 }
 
-public abstract interface class space/kscience/kmath/linear/LinearSpace {
+public abstract interface class space/kscience/kmath/linear/LinearSpace : space/kscience/kmath/linear/MatrixScope {
 	public static final field Companion Lspace/kscience/kmath/linear/LinearSpace$Companion;
 	public abstract fun buildMatrix (IILkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/Structure2D;
 	public abstract fun buildVector (ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/structures/Buffer;
+	public fun computeAttribute (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/StructureAttribute;)Ljava/lang/Object;
 	public fun dot (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D;
 	public fun dot (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
 	public abstract fun getElementAlgebra ()Lspace/kscience/kmath/operations/Ring;
+	public fun getType-V0oMfBY ()Lkotlin/reflect/KType;
 	public fun minus (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D;
 	public fun minus (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
 	public fun plus (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D;
@@ -665,39 +744,54 @@ public final class space/kscience/kmath/linear/LinearSpaceKt {
 	public static final fun invoke (Lspace/kscience/kmath/linear/LinearSpace;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
 }
 
-public final class space/kscience/kmath/linear/LupDecomposition : space/kscience/kmath/linear/DeterminantFeature, space/kscience/kmath/linear/LupDecompositionFeature {
-	public fun <init> (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/operations/Field;Lspace/kscience/kmath/nd/Structure2D;[IZ)V
-	public final fun getContext ()Lspace/kscience/kmath/linear/LinearSpace;
-	public fun getDeterminant ()Ljava/lang/Object;
-	public final fun getElementContext ()Lspace/kscience/kmath/operations/Field;
-	public fun getL ()Lspace/kscience/kmath/nd/Structure2D;
-	public final fun getLu ()Lspace/kscience/kmath/nd/Structure2D;
-	public fun getP ()Lspace/kscience/kmath/nd/Structure2D;
-	public final fun getPivot ()[I
-	public fun getU ()Lspace/kscience/kmath/nd/Structure2D;
+public final class space/kscience/kmath/linear/LowerTriangular : space/kscience/attributes/FlagAttribute, space/kscience/kmath/linear/MatrixAttribute {
+	public static final field INSTANCE Lspace/kscience/kmath/linear/LowerTriangular;
 }
 
-public abstract interface class space/kscience/kmath/linear/LupDecompositionFeature : space/kscience/kmath/linear/MatrixFeature {
+public final class space/kscience/kmath/linear/LuDecompositionAttribute : space/kscience/attributes/PolymorphicAttribute, space/kscience/kmath/linear/MatrixAttribute {
+	public fun <init> ()V
+}
+
+public abstract interface class space/kscience/kmath/linear/LupDecomposition {
 	public abstract fun getL ()Lspace/kscience/kmath/nd/Structure2D;
-	public abstract fun getP ()Lspace/kscience/kmath/nd/Structure2D;
+	public abstract fun getPivot-M_oXE9g ()[I
 	public abstract fun getU ()Lspace/kscience/kmath/nd/Structure2D;
 }
 
+public final class space/kscience/kmath/linear/LupDecompositionAttribute : space/kscience/attributes/PolymorphicAttribute, space/kscience/kmath/linear/MatrixAttribute {
+	public fun <init> ()V
+}
+
 public final class space/kscience/kmath/linear/LupDecompositionKt {
 	public static final fun abs (Lspace/kscience/kmath/linear/LinearSpace;Ljava/lang/Comparable;)Ljava/lang/Comparable;
-	public static final fun lup (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/nd/Structure2D;D)Lspace/kscience/kmath/linear/LupDecomposition;
-	public static final fun lup (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/structures/MutableBufferFactory;Lspace/kscience/kmath/nd/Structure2D;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/linear/LupDecomposition;
-	public static synthetic fun lup$default (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/nd/Structure2D;DILjava/lang/Object;)Lspace/kscience/kmath/linear/LupDecomposition;
+	public static final fun getLUP (Lspace/kscience/kmath/linear/MatrixScope;)Lspace/kscience/kmath/linear/LupDecompositionAttribute;
+	public static final fun lup (Lspace/kscience/kmath/operations/Field;Lspace/kscience/kmath/nd/Structure2D;D)Lspace/kscience/kmath/linear/GenericLupDecomposition;
+	public static final fun lup (Lspace/kscience/kmath/operations/Field;Lspace/kscience/kmath/nd/Structure2D;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/linear/GenericLupDecomposition;
+	public static synthetic fun lup$default (Lspace/kscience/kmath/operations/Field;Lspace/kscience/kmath/nd/Structure2D;DILjava/lang/Object;)Lspace/kscience/kmath/linear/GenericLupDecomposition;
 	public static final fun lupSolver (Lspace/kscience/kmath/linear/LinearSpace;D)Lspace/kscience/kmath/linear/LinearSolver;
-	public static final fun lupSolver (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/structures/MutableBufferFactory;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/linear/LinearSolver;
+	public static final fun lupSolver (Lspace/kscience/kmath/linear/LinearSpace;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/linear/LinearSolver;
 	public static synthetic fun lupSolver$default (Lspace/kscience/kmath/linear/LinearSpace;DILjava/lang/Object;)Lspace/kscience/kmath/linear/LinearSolver;
+	public static final fun pivotMatrix (Lspace/kscience/kmath/linear/LupDecomposition;Lspace/kscience/kmath/linear/LinearSpace;)Lspace/kscience/kmath/nd/Structure2D;
 }
 
-public final class space/kscience/kmath/linear/MatrixBuilder {
+public abstract interface class space/kscience/kmath/linear/MatrixAttribute : space/kscience/kmath/nd/StructureAttribute {
+}
+
+public final class space/kscience/kmath/linear/MatrixAttributesKt {
+	public static final fun getCholesky (Lspace/kscience/kmath/linear/MatrixScope;)Lspace/kscience/kmath/linear/CholeskyDecompositionAttribute;
+	public static final fun getDeterminant (Lspace/kscience/kmath/linear/MatrixScope;)Lspace/kscience/kmath/linear/Determinant;
+	public static final fun getInverted (Lspace/kscience/kmath/linear/MatrixScope;)Lspace/kscience/kmath/linear/Inverted;
+	public static final fun getLU (Lspace/kscience/kmath/linear/MatrixScope;)Lspace/kscience/kmath/linear/LuDecompositionAttribute;
+	public static final fun getQR (Lspace/kscience/kmath/linear/MatrixScope;)Lspace/kscience/kmath/linear/QRDecompositionAttribute;
+	public static final fun getSVD (Lspace/kscience/kmath/linear/MatrixScope;)Lspace/kscience/kmath/linear/SVDAttribute;
+}
+
+public final class space/kscience/kmath/linear/MatrixBuilder : space/kscience/attributes/WithType {
 	public fun <init> (Lspace/kscience/kmath/linear/LinearSpace;II)V
 	public final fun getColumns ()I
 	public final fun getLinearSpace ()Lspace/kscience/kmath/linear/LinearSpace;
 	public final fun getRows ()I
+	public fun getType-V0oMfBY ()Lkotlin/reflect/KType;
 	public final fun invoke ([Ljava/lang/Object;)Lspace/kscience/kmath/nd/Structure2D;
 }
 
@@ -709,23 +803,17 @@ public final class space/kscience/kmath/linear/MatrixBuilderKt {
 	public static final fun symmetric (Lspace/kscience/kmath/linear/MatrixBuilder;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/Structure2D;
 }
 
-public abstract interface class space/kscience/kmath/linear/MatrixFeature : space/kscience/kmath/nd/StructureFeature {
-}
-
-public final class space/kscience/kmath/linear/MatrixFeaturesKt {
-	public static final fun DeterminantFeature (Ljava/lang/Object;)Lspace/kscience/kmath/linear/DeterminantFeature;
+public abstract interface class space/kscience/kmath/linear/MatrixScope : space/kscience/attributes/AttributeScope, space/kscience/attributes/WithType {
 }
 
 public final class space/kscience/kmath/linear/MatrixWrapper : space/kscience/kmath/nd/Structure2D {
 	public fun elements ()Lkotlin/sequences/Sequence;
 	public fun get (II)Ljava/lang/Object;
 	public fun get ([I)Ljava/lang/Object;
+	public fun getAttributes ()Lspace/kscience/attributes/Attributes;
 	public fun getColNum ()I
 	public fun getColumns ()Ljava/util/List;
 	public fun getDimension ()I
-	public synthetic fun getFeature (Lkotlin/reflect/KClass;)Ljava/lang/Object;
-	public fun getFeature (Lkotlin/reflect/KClass;)Lspace/kscience/kmath/nd/StructureFeature;
-	public final fun getFeatures-En6fw3w ()Ljava/util/Map;
 	public fun getIndices ()Lspace/kscience/kmath/nd/ShapeIndexer;
 	public final fun getOrigin ()Lspace/kscience/kmath/nd/Structure2D;
 	public fun getRowNum ()I
@@ -735,50 +823,63 @@ public final class space/kscience/kmath/linear/MatrixWrapper : space/kscience/km
 }
 
 public final class space/kscience/kmath/linear/MatrixWrapperKt {
-	public static final fun one (Lspace/kscience/kmath/linear/LinearSpace;II)Lspace/kscience/kmath/nd/Structure2D;
-	public static final fun plus (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/linear/MatrixFeature;)Lspace/kscience/kmath/linear/MatrixWrapper;
-	public static final fun transpose (Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D;
-	public static final fun withFeature (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/linear/MatrixFeature;)Lspace/kscience/kmath/linear/MatrixWrapper;
-	public static final fun withFeatures (Lspace/kscience/kmath/nd/Structure2D;Ljava/lang/Iterable;)Lspace/kscience/kmath/linear/MatrixWrapper;
-	public static final fun zero (Lspace/kscience/kmath/linear/LinearSpace;II)Lspace/kscience/kmath/nd/Structure2D;
+	public static final fun modifyAttributes (Lspace/kscience/kmath/nd/Structure2D;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/linear/MatrixWrapper;
+	public static final fun one (Lspace/kscience/kmath/linear/LinearSpace;II)Lspace/kscience/kmath/linear/MatrixWrapper;
+	public static final fun withAttribute (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/attributes/Attribute;)Lspace/kscience/kmath/linear/MatrixWrapper;
+	public static final fun withAttribute (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/attributes/Attribute;Ljava/lang/Object;)Lspace/kscience/kmath/linear/MatrixWrapper;
+	public static final fun zero (Lspace/kscience/kmath/linear/LinearSpace;II)Lspace/kscience/kmath/linear/MatrixWrapper;
 }
 
-public final class space/kscience/kmath/linear/OrthogonalFeature : space/kscience/kmath/linear/MatrixFeature {
-	public static final field INSTANCE Lspace/kscience/kmath/linear/OrthogonalFeature;
+public final class space/kscience/kmath/linear/OrthogonalAttribute : space/kscience/attributes/FlagAttribute, space/kscience/kmath/linear/MatrixAttribute {
+	public static final field INSTANCE Lspace/kscience/kmath/linear/OrthogonalAttribute;
 }
 
-public abstract interface class space/kscience/kmath/linear/QRDecompositionFeature : space/kscience/kmath/linear/MatrixFeature {
+public abstract interface class space/kscience/kmath/linear/QRDecomposition {
 	public abstract fun getQ ()Lspace/kscience/kmath/nd/Structure2D;
 	public abstract fun getR ()Lspace/kscience/kmath/nd/Structure2D;
 }
 
-public abstract interface class space/kscience/kmath/linear/SingularValueDecompositionFeature : space/kscience/kmath/linear/MatrixFeature {
+public final class space/kscience/kmath/linear/QRDecompositionAttribute : space/kscience/attributes/PolymorphicAttribute, space/kscience/kmath/linear/MatrixAttribute {
+	public fun <init> ()V
+}
+
+public final class space/kscience/kmath/linear/SVDAttribute : space/kscience/attributes/PolymorphicAttribute, space/kscience/kmath/linear/MatrixAttribute {
+	public fun <init> ()V
+}
+
+public abstract interface class space/kscience/kmath/linear/SingularValueDecomposition {
 	public abstract fun getS ()Lspace/kscience/kmath/nd/Structure2D;
 	public abstract fun getSingularValues ()Lspace/kscience/kmath/structures/Buffer;
 	public abstract fun getU ()Lspace/kscience/kmath/nd/Structure2D;
 	public abstract fun getV ()Lspace/kscience/kmath/nd/Structure2D;
 }
 
-public final class space/kscience/kmath/linear/SymmetricMatrixFeature : space/kscience/kmath/linear/MatrixFeature {
-	public static final field INSTANCE Lspace/kscience/kmath/linear/SymmetricMatrixFeature;
+public final class space/kscience/kmath/linear/Symmetric : space/kscience/attributes/FlagAttribute, space/kscience/kmath/linear/MatrixAttribute {
+	public static final field INSTANCE Lspace/kscience/kmath/linear/Symmetric;
 }
 
-public final class space/kscience/kmath/linear/TransposedFeature : space/kscience/kmath/linear/MatrixFeature {
+public final class space/kscience/kmath/linear/TransposedKt {
+	public static final fun transposed (Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D;
+}
+
+public final class space/kscience/kmath/linear/TransposedMatrix : space/kscience/kmath/nd/Structure2D {
 	public fun <init> (Lspace/kscience/kmath/nd/Structure2D;)V
-	public final fun getOriginal ()Lspace/kscience/kmath/nd/Structure2D;
+	public fun get (II)Ljava/lang/Object;
+	public fun getAttributes ()Lspace/kscience/attributes/Attributes;
+	public fun getColNum ()I
+	public final fun getOrigin ()Lspace/kscience/kmath/nd/Structure2D;
+	public fun getRowNum ()I
 }
 
-public final class space/kscience/kmath/linear/UFeature : space/kscience/kmath/linear/MatrixFeature {
-	public static final field INSTANCE Lspace/kscience/kmath/linear/UFeature;
-}
-
-public final class space/kscience/kmath/linear/UnitFeature : space/kscience/kmath/linear/DiagonalFeature {
-	public static final field INSTANCE Lspace/kscience/kmath/linear/UnitFeature;
+public final class space/kscience/kmath/linear/UpperTriangular : space/kscience/attributes/FlagAttribute, space/kscience/kmath/linear/MatrixAttribute {
+	public static final field INSTANCE Lspace/kscience/kmath/linear/UpperTriangular;
 }
 
 public final class space/kscience/kmath/linear/VirtualMatrix : space/kscience/kmath/nd/Structure2D {
-	public fun <init> (IILkotlin/jvm/functions/Function2;)V
+	public fun <init> (IILspace/kscience/attributes/Attributes;Lkotlin/jvm/functions/Function2;)V
+	public synthetic fun <init> (IILspace/kscience/attributes/Attributes;Lkotlin/jvm/functions/Function2;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
 	public fun get (II)Ljava/lang/Object;
+	public fun getAttributes ()Lspace/kscience/attributes/Attributes;
 	public fun getColNum ()I
 	public final fun getGenerator ()Lkotlin/jvm/functions/Function2;
 	public fun getRowNum ()I
@@ -786,11 +887,8 @@ public final class space/kscience/kmath/linear/VirtualMatrix : space/kscience/km
 }
 
 public final class space/kscience/kmath/linear/VirtualMatrixKt {
-	public static final fun virtual (Lspace/kscience/kmath/linear/MatrixBuilder;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/linear/VirtualMatrix;
-}
-
-public final class space/kscience/kmath/linear/ZeroFeature : space/kscience/kmath/linear/DiagonalFeature {
-	public static final field INSTANCE Lspace/kscience/kmath/linear/ZeroFeature;
+	public static final fun virtual (Lspace/kscience/kmath/linear/MatrixBuilder;Lspace/kscience/attributes/Attributes;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/linear/VirtualMatrix;
+	public static synthetic fun virtual$default (Lspace/kscience/kmath/linear/MatrixBuilder;Lspace/kscience/attributes/Attributes;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lspace/kscience/kmath/linear/VirtualMatrix;
 }
 
 public final class space/kscience/kmath/misc/CollectionsKt {
@@ -818,42 +916,6 @@ public final class space/kscience/kmath/misc/CumulativeKt {
 	public static final fun cumulativeSumOfLong (Lkotlin/sequences/Sequence;)Lkotlin/sequences/Sequence;
 }
 
-public abstract interface class space/kscience/kmath/misc/Feature {
-	public fun getKey ()Lkotlin/reflect/KClass;
-}
-
-public final class space/kscience/kmath/misc/FeatureSet : space/kscience/kmath/misc/Featured {
-	public static final field Companion Lspace/kscience/kmath/misc/FeatureSet$Companion;
-	public static final synthetic fun box-impl (Ljava/util/Map;)Lspace/kscience/kmath/misc/FeatureSet;
-	public fun equals (Ljava/lang/Object;)Z
-	public static fun equals-impl (Ljava/util/Map;Ljava/lang/Object;)Z
-	public static final fun equals-impl0 (Ljava/util/Map;Ljava/util/Map;)Z
-	public synthetic fun getFeature (Lkotlin/reflect/KClass;)Ljava/lang/Object;
-	public fun getFeature (Lkotlin/reflect/KClass;)Lspace/kscience/kmath/misc/Feature;
-	public static fun getFeature-impl (Ljava/util/Map;Lkotlin/reflect/KClass;)Lspace/kscience/kmath/misc/Feature;
-	public final fun getFeatures ()Ljava/util/Map;
-	public fun hashCode ()I
-	public static fun hashCode-impl (Ljava/util/Map;)I
-	public static final fun iterator-impl (Ljava/util/Map;)Ljava/util/Iterator;
-	public fun toString ()Ljava/lang/String;
-	public static fun toString-impl (Ljava/util/Map;)Ljava/lang/String;
-	public final synthetic fun unbox-impl ()Ljava/util/Map;
-	public static final fun with-JVE9-Rk (Ljava/util/Map;Ljava/lang/Iterable;)Ljava/util/Map;
-	public static final fun with-JVE9-Rk (Ljava/util/Map;[Lspace/kscience/kmath/misc/Feature;)Ljava/util/Map;
-	public static final fun with-YU1a0hQ (Ljava/util/Map;Ljava/util/Map;)Ljava/util/Map;
-	public static final fun with-h58Sd8I (Ljava/util/Map;Lspace/kscience/kmath/misc/Feature;Lkotlin/reflect/KClass;)Ljava/util/Map;
-	public static synthetic fun with-h58Sd8I$default (Ljava/util/Map;Lspace/kscience/kmath/misc/Feature;Lkotlin/reflect/KClass;ILjava/lang/Object;)Ljava/util/Map;
-}
-
-public final class space/kscience/kmath/misc/FeatureSet$Companion {
-	public final fun of-JVE9-Rk (Ljava/lang/Iterable;)Ljava/util/Map;
-	public final fun of-JVE9-Rk ([Lspace/kscience/kmath/misc/Feature;)Ljava/util/Map;
-}
-
-public abstract interface class space/kscience/kmath/misc/Featured {
-	public abstract fun getFeature (Lkotlin/reflect/KClass;)Ljava/lang/Object;
-}
-
 public abstract interface class space/kscience/kmath/misc/Loggable {
 	public static final field Companion Lspace/kscience/kmath/misc/Loggable$Companion;
 	public static final field INFO Ljava/lang/String;
@@ -879,6 +941,7 @@ public final class space/kscience/kmath/misc/SortingKt {
 	public static final fun sortedBy (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer;
 	public static final fun sortedByDescending (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer;
 	public static final fun sortedDescending (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
+	public static final fun sortedWith (Lspace/kscience/kmath/structures/Buffer;Ljava/util/Comparator;)Lspace/kscience/kmath/structures/Buffer;
 }
 
 public abstract interface class space/kscience/kmath/nd/AlgebraND : space/kscience/kmath/operations/Algebra {
@@ -887,7 +950,8 @@ public abstract interface class space/kscience/kmath/nd/AlgebraND : space/kscien
 	public fun invoke (Lkotlin/jvm/functions/Function1;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
 	public fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND;
 	public fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND;
-	public abstract fun structureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND;
+	public abstract fun mutableStructureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun structureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND;
 	public fun zip (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND;
 }
 
@@ -895,6 +959,7 @@ public final class space/kscience/kmath/nd/AlgebraND$Companion {
 }
 
 public final class space/kscience/kmath/nd/AlgebraNDExtentionsKt {
+	public static final fun mutableStructureND (Lspace/kscience/kmath/nd/AlgebraND;I[ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/MutableStructureND;
 	public static final fun one-waz_sdI (Lspace/kscience/kmath/nd/AlgebraND;[I)Lspace/kscience/kmath/nd/StructureND;
 	public static final fun oneVarArg (Lspace/kscience/kmath/nd/AlgebraND;I[I)Lspace/kscience/kmath/nd/StructureND;
 	public static final fun structureND (Lspace/kscience/kmath/nd/AlgebraND;I[ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND;
@@ -911,6 +976,8 @@ public abstract interface class space/kscience/kmath/nd/BufferAlgebraND : space/
 	public synthetic fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND;
 	public fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/BufferND;
 	public synthetic fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND;
+	public fun mutableStructureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/MutableBufferND;
+	public synthetic fun mutableStructureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/MutableStructureND;
 	public fun structureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND;
 	public synthetic fun structureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND;
 	public fun toBufferND (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND;
@@ -927,6 +994,7 @@ public final class space/kscience/kmath/nd/BufferAlgebraNDKt {
 	public static final fun getNd (Lspace/kscience/kmath/operations/BufferAlgebra;)Lspace/kscience/kmath/nd/BufferedGroupNDOps;
 	public static final fun getNd (Lspace/kscience/kmath/operations/BufferAlgebra;)Lspace/kscience/kmath/nd/BufferedRingOpsND;
 	public static final fun mapInline (Lspace/kscience/kmath/nd/BufferAlgebraND;Lspace/kscience/kmath/nd/BufferND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND;
+	public static final fun mutableStructureND (Lspace/kscience/kmath/nd/BufferAlgebraND;[ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/MutableBufferND;
 	public static final fun structureND (Lspace/kscience/kmath/nd/BufferAlgebraND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND;
 	public static final fun structureND (Lspace/kscience/kmath/nd/BufferAlgebraND;[ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND;
 }
@@ -940,13 +1008,6 @@ public class space/kscience/kmath/nd/BufferND : space/kscience/kmath/nd/Structur
 	public fun toString ()Ljava/lang/String;
 }
 
-public final class space/kscience/kmath/nd/BufferNDKt {
-	public static final fun BufferND-bYNkpeI ([ILspace/kscience/kmath/structures/BufferFactory;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/BufferND;
-	public static synthetic fun BufferND-bYNkpeI$default ([ILspace/kscience/kmath/structures/BufferFactory;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/kmath/nd/BufferND;
-	public static final fun MutableBufferND-bYNkpeI ([ILspace/kscience/kmath/structures/MutableBufferFactory;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/MutableBufferND;
-	public static synthetic fun MutableBufferND-bYNkpeI$default ([ILspace/kscience/kmath/structures/MutableBufferFactory;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/kmath/nd/MutableBufferND;
-}
-
 public class space/kscience/kmath/nd/BufferedFieldOpsND : space/kscience/kmath/nd/BufferedRingOpsND, space/kscience/kmath/nd/FieldOpsND {
 	public fun <init> (Lspace/kscience/kmath/operations/BufferAlgebra;Lkotlin/jvm/functions/Function1;)V
 	public synthetic fun <init> (Lspace/kscience/kmath/operations/BufferAlgebra;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
@@ -961,6 +1022,7 @@ public class space/kscience/kmath/nd/BufferedGroupNDOps : space/kscience/kmath/n
 	public synthetic fun <init> (Lspace/kscience/kmath/operations/BufferAlgebra;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
 	public fun getBufferAlgebra ()Lspace/kscience/kmath/operations/BufferAlgebra;
 	public fun getIndexerBuilder ()Lkotlin/jvm/functions/Function1;
+	public fun getType-V0oMfBY ()Lkotlin/reflect/KType;
 	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
 	public fun unaryMinus (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
 }
@@ -983,137 +1045,6 @@ public final class space/kscience/kmath/nd/ColumnStrides : space/kscience/kmath/
 public final class space/kscience/kmath/nd/ColumnStrides$Companion {
 }
 
-public final class space/kscience/kmath/nd/DoubleBufferND : space/kscience/kmath/nd/MutableBufferND, space/kscience/kmath/nd/MutableStructureNDOfDouble {
-	public synthetic fun <init> (Lspace/kscience/kmath/nd/ShapeIndexer;[DLkotlin/jvm/internal/DefaultConstructorMarker;)V
-	public synthetic fun getBuffer ()Lspace/kscience/kmath/structures/Buffer;
-	public synthetic fun getBuffer ()Lspace/kscience/kmath/structures/MutableBuffer;
-	public fun getBuffer-Dv3HvWU ()[D
-	public fun getDouble ([I)D
-	public fun setDouble ([ID)V
-}
-
-public final class space/kscience/kmath/nd/DoubleFieldND : space/kscience/kmath/nd/DoubleFieldOpsND, space/kscience/kmath/nd/FieldND, space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/NumbersAddOps {
-	public synthetic fun <init> ([ILkotlin/jvm/internal/DefaultConstructorMarker;)V
-	public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun acosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun asinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun atanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun cosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public fun getShape-IIYLAfE ()[I
-	public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
-	public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun power (Ljava/lang/Object;I)Ljava/lang/Object;
-	public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
-	public fun power (Lspace/kscience/kmath/nd/StructureND;I)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public fun power (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun power (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd/StructureND;
-	public synthetic fun power-Qn1smSk (Ljava/lang/Object;I)Ljava/lang/Object;
-	public fun power-Qn1smSk (Lspace/kscience/kmath/nd/StructureND;I)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun sinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun tanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-}
-
-public final class space/kscience/kmath/nd/DoubleFieldNDKt {
-	public static final fun getNdAlgebra (Lspace/kscience/kmath/operations/DoubleField;)Lspace/kscience/kmath/nd/DoubleFieldOpsND;
-	public static final fun ndAlgebra (Lspace/kscience/kmath/operations/DoubleField;[I)Lspace/kscience/kmath/nd/DoubleFieldND;
-	public static final fun ndAlgebra-waz_sdI (Lspace/kscience/kmath/operations/DoubleField;[I)Lspace/kscience/kmath/nd/DoubleFieldND;
-}
-
-public abstract class space/kscience/kmath/nd/DoubleFieldOpsND : space/kscience/kmath/nd/BufferedFieldOpsND, space/kscience/kmath/operations/ExtendedFieldOps, space/kscience/kmath/operations/ScaleOperations {
-	public static final field Companion Lspace/kscience/kmath/nd/DoubleFieldOpsND$Companion;
-	public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun acos (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun acosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun add (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun add (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
-	public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun asin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun asinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun atan (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun atanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun cos (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun cosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public fun div (DLspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun div (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
-	public synthetic fun div (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public synthetic fun div (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
-	public fun div (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public fun div (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun div (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
-	public fun div (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun divide (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun divide (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
-	public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun exp (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun ln (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND;
-	public synthetic fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND;
-	protected final fun mapInline (Lspace/kscience/kmath/nd/DoubleBufferND;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public fun minus (DLspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
-	public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public synthetic fun minus (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
-	public fun minus (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/StructureND;
-	public synthetic fun minus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
-	public fun minus (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun multiply (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun multiply (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
-	public fun plus (DLspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
-	public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public synthetic fun plus (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
-	public fun plus (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun plus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
-	public fun plus (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
-	public fun power (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd/StructureND;
-	public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object;
-	public fun scale (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun scale (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/StructureND;
-	public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun sin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun sinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun structureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND;
-	public fun structureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun structureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND;
-	public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun tan (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun tanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun times (Ljava/lang/Number;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun times (Ljava/lang/Number;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun times (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
-	public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun times (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public fun times (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun toBufferND (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND;
-	public fun toBufferND (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun unaryMinus (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public synthetic fun unaryMinus (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
-	public synthetic fun unaryPlus (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun unaryPlus (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/DoubleBufferND;
-	public fun zip (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/BufferND;
-	public synthetic fun zip (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND;
-}
-
-public final class space/kscience/kmath/nd/DoubleFieldOpsND$Companion : space/kscience/kmath/nd/DoubleFieldOpsND {
-}
-
 public abstract interface class space/kscience/kmath/nd/FieldND : space/kscience/kmath/nd/FieldOpsND, space/kscience/kmath/nd/RingND, space/kscience/kmath/nd/WithShape, space/kscience/kmath/operations/Field {
 	public synthetic fun getOne ()Ljava/lang/Object;
 	public fun getOne ()Lspace/kscience/kmath/nd/StructureND;
@@ -1128,6 +1059,137 @@ public abstract interface class space/kscience/kmath/nd/FieldOpsND : space/kscie
 	public fun scale (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/StructureND;
 }
 
+public abstract class space/kscience/kmath/nd/Floa64FieldOpsND : space/kscience/kmath/nd/BufferedFieldOpsND, space/kscience/kmath/operations/ExtendedFieldOps, space/kscience/kmath/operations/ScaleOperations {
+	public static final field Companion Lspace/kscience/kmath/nd/Floa64FieldOpsND$Companion;
+	public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun acos (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun acosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun add (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun add (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun asin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun asinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun atan (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun atanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun cos (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun cosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public fun div (DLspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun div (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
+	public synthetic fun div (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun div (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun div (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/Float64BufferND;
+	public fun div (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun div (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
+	public fun div (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun divide (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun divide (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun exp (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun ln (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND;
+	public synthetic fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND;
+	protected final fun mapInline (Lspace/kscience/kmath/nd/Float64BufferND;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public fun minus (DLspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun minus (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun minus (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun minus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
+	public fun minus (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun multiply (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun multiply (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun mutableStructureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun mutableStructureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/MutableBufferND;
+	public synthetic fun mutableStructureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun plus (DLspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun plus (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun plus (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun plus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
+	public fun plus (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
+	public fun power (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object;
+	public fun scale (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun scale (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun sin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun sinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun tan (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun tanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun times (Ljava/lang/Number;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun times (Ljava/lang/Number;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun times (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
+	public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun times (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public fun times (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun toBufferND (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND;
+	public fun toBufferND (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun unaryMinus (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun unaryMinus (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun unaryPlus (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun unaryPlus (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public fun zip (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/BufferND;
+	public synthetic fun zip (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND;
+}
+
+public final class space/kscience/kmath/nd/Floa64FieldOpsND$Companion : space/kscience/kmath/nd/Floa64FieldOpsND {
+}
+
+public final class space/kscience/kmath/nd/Float64BufferND : space/kscience/kmath/nd/MutableBufferND, space/kscience/kmath/nd/MutableStructureNDOfDouble {
+	public synthetic fun <init> (Lspace/kscience/kmath/nd/ShapeIndexer;[DLkotlin/jvm/internal/DefaultConstructorMarker;)V
+	public synthetic fun getBuffer ()Lspace/kscience/kmath/structures/Buffer;
+	public synthetic fun getBuffer ()Lspace/kscience/kmath/structures/MutableBuffer;
+	public fun getBuffer-E20IKn8 ()[D
+	public fun getDouble ([I)D
+	public fun setDouble ([ID)V
+}
+
+public final class space/kscience/kmath/nd/Float64FieldND : space/kscience/kmath/nd/Floa64FieldOpsND, space/kscience/kmath/nd/FieldND, space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/NumbersAddOps {
+	public synthetic fun <init> ([ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+	public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun acosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun asinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun atanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun cosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public fun getShape-IIYLAfE ()[I
+	public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
+	public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun power (Ljava/lang/Object;I)Ljava/lang/Object;
+	public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
+	public fun power (Lspace/kscience/kmath/nd/StructureND;I)Lspace/kscience/kmath/nd/Float64BufferND;
+	public fun power (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun power (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun power-Qn1smSk (Ljava/lang/Object;I)Ljava/lang/Object;
+	public fun power-Qn1smSk (Lspace/kscience/kmath/nd/StructureND;I)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun sinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+	public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun tanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Float64BufferND;
+}
+
+public final class space/kscience/kmath/nd/Float64FieldNDKt {
+	public static final fun getNdAlgebra (Lspace/kscience/kmath/operations/Float64Field;)Lspace/kscience/kmath/nd/Floa64FieldOpsND;
+	public static final fun ndAlgebra (Lspace/kscience/kmath/operations/Float64Field;[I)Lspace/kscience/kmath/nd/Float64FieldND;
+	public static final fun ndAlgebra-waz_sdI (Lspace/kscience/kmath/operations/Float64Field;[I)Lspace/kscience/kmath/nd/Float64FieldND;
+}
+
 public abstract interface class space/kscience/kmath/nd/GroupND : space/kscience/kmath/nd/GroupOpsND, space/kscience/kmath/nd/WithShape, space/kscience/kmath/operations/Group {
 	public synthetic fun getZero ()Ljava/lang/Object;
 	public fun getZero ()Lspace/kscience/kmath/nd/StructureND;
@@ -1137,6 +1199,7 @@ public abstract interface class space/kscience/kmath/nd/GroupOpsND : space/kscie
 	public static final field Companion Lspace/kscience/kmath/nd/GroupOpsND$Companion;
 	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
 	public fun add (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
 	public fun minus (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
 	public fun minus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
 	public fun plus (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
@@ -1152,11 +1215,29 @@ public final class space/kscience/kmath/nd/IndexOutOfShapeException : java/lang/
 	public final fun getShape-IIYLAfE ()[I
 }
 
+public final class space/kscience/kmath/nd/Int16RingND : space/kscience/kmath/nd/Int16RingOpsND, space/kscience/kmath/nd/RingND, space/kscience/kmath/operations/NumbersAddOps {
+	public synthetic fun <init> ([ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+	public fun getShape-IIYLAfE ()[I
+	public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
+	public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/nd/BufferND;
+}
+
+public final class space/kscience/kmath/nd/Int16RingNDKt {
+	public static final fun withNdAlgebra (Lspace/kscience/kmath/operations/Int16Ring;[ILkotlin/jvm/functions/Function1;)Ljava/lang/Object;
+}
+
+public abstract class space/kscience/kmath/nd/Int16RingOpsND : space/kscience/kmath/nd/BufferedRingOpsND {
+	public static final field Companion Lspace/kscience/kmath/nd/Int16RingOpsND$Companion;
+}
+
+public final class space/kscience/kmath/nd/Int16RingOpsND$Companion : space/kscience/kmath/nd/Int16RingOpsND {
+}
+
 public final class space/kscience/kmath/nd/IntBufferND : space/kscience/kmath/nd/MutableBufferND {
 	public synthetic fun <init> (Lspace/kscience/kmath/nd/ShapeIndexer;[ILkotlin/jvm/internal/DefaultConstructorMarker;)V
 	public synthetic fun getBuffer ()Lspace/kscience/kmath/structures/Buffer;
 	public synthetic fun getBuffer ()Lspace/kscience/kmath/structures/MutableBuffer;
-	public fun getBuffer-ir4F4A8 ()[I
+	public fun getBuffer-M_oXE9g ()[I
 }
 
 public final class space/kscience/kmath/nd/IntRingND : space/kscience/kmath/nd/IntRingOpsND, space/kscience/kmath/nd/RingND, space/kscience/kmath/operations/NumbersAddOps {
@@ -1167,7 +1248,7 @@ public final class space/kscience/kmath/nd/IntRingND : space/kscience/kmath/nd/I
 }
 
 public final class space/kscience/kmath/nd/IntRingNDKt {
-	public static final fun withNdAlgebra (Lspace/kscience/kmath/operations/IntRing;[ILkotlin/jvm/functions/Function1;)Ljava/lang/Object;
+	public static final fun withNdAlgebra (Lspace/kscience/kmath/operations/Int32Ring;[ILkotlin/jvm/functions/Function1;)Ljava/lang/Object;
 }
 
 public abstract class space/kscience/kmath/nd/IntRingOpsND : space/kscience/kmath/nd/BufferedRingOpsND {
@@ -1201,6 +1282,15 @@ public abstract interface class space/kscience/kmath/nd/MutableStructureND : spa
 	public abstract fun set ([ILjava/lang/Object;)V
 }
 
+public final class space/kscience/kmath/nd/MutableStructureNDAccessorBuffer : space/kscience/kmath/structures/MutableBuffer {
+	public fun <init> (Lspace/kscience/kmath/nd/MutableStructureND;ILkotlin/jvm/functions/Function1;)V
+	public fun get (I)Ljava/lang/Object;
+	public fun getSize ()I
+	public final fun getStructure ()Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun set (ILjava/lang/Object;)V
+	public fun toString ()Ljava/lang/String;
+}
+
 public abstract interface class space/kscience/kmath/nd/MutableStructureNDOfDouble : space/kscience/kmath/nd/MutableStructureND, space/kscience/kmath/nd/StructureNDOfDouble {
 	public abstract fun setDouble ([ID)V
 }
@@ -1332,24 +1422,6 @@ public final class space/kscience/kmath/nd/ShapeNDKt {
 	public static final fun transposed-bYNkpeI ([III)[I
 }
 
-public final class space/kscience/kmath/nd/ShortRingND : space/kscience/kmath/nd/ShortRingOpsND, space/kscience/kmath/nd/RingND, space/kscience/kmath/operations/NumbersAddOps {
-	public synthetic fun <init> ([ILkotlin/jvm/internal/DefaultConstructorMarker;)V
-	public fun getShape-IIYLAfE ()[I
-	public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
-	public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/nd/BufferND;
-}
-
-public final class space/kscience/kmath/nd/ShortRingNDKt {
-	public static final fun withNdAlgebra (Lspace/kscience/kmath/operations/ShortRing;[ILkotlin/jvm/functions/Function1;)Ljava/lang/Object;
-}
-
-public abstract class space/kscience/kmath/nd/ShortRingOpsND : space/kscience/kmath/nd/BufferedRingOpsND {
-	public static final field Companion Lspace/kscience/kmath/nd/ShortRingOpsND$Companion;
-}
-
-public final class space/kscience/kmath/nd/ShortRingOpsND$Companion : space/kscience/kmath/nd/ShortRingOpsND {
-}
-
 public abstract class space/kscience/kmath/nd/Strides : space/kscience/kmath/nd/ShapeIndexer {
 	public fun <init> ()V
 	public fun asSequence ()Lkotlin/sequences/Sequence;
@@ -1392,26 +1464,19 @@ public final class space/kscience/kmath/nd/Structure2DKt {
 	public static final fun as2D (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Structure2D;
 }
 
-public abstract interface class space/kscience/kmath/nd/StructureFeature : space/kscience/kmath/misc/Feature {
+public abstract interface class space/kscience/kmath/nd/StructureAttribute : space/kscience/attributes/Attribute {
 }
 
-public abstract interface class space/kscience/kmath/nd/StructureND : space/kscience/kmath/misc/Featured, space/kscience/kmath/nd/WithShape {
+public abstract interface class space/kscience/kmath/nd/StructureND : space/kscience/attributes/AttributeContainer, space/kscience/kmath/nd/WithShape {
 	public static final field Companion Lspace/kscience/kmath/nd/StructureND$Companion;
 	public fun elements ()Lkotlin/sequences/Sequence;
 	public abstract fun get ([I)Ljava/lang/Object;
+	public fun getAttributes ()Lspace/kscience/attributes/Attributes;
 	public fun getDimension ()I
-	public synthetic fun getFeature (Lkotlin/reflect/KClass;)Ljava/lang/Object;
-	public fun getFeature (Lkotlin/reflect/KClass;)Lspace/kscience/kmath/nd/StructureFeature;
 	public abstract fun getShape-IIYLAfE ()[I
 }
 
 public final class space/kscience/kmath/nd/StructureND$Companion {
-	public final fun auto (Lkotlin/reflect/KClass;Lspace/kscience/kmath/nd/Strides;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/BufferND;
-	public final fun auto (Lkotlin/reflect/KClass;[ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/BufferND;
-	public final fun buffered (Lspace/kscience/kmath/nd/Strides;Lspace/kscience/kmath/structures/BufferFactory;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/BufferND;
-	public static synthetic fun buffered$default (Lspace/kscience/kmath/nd/StructureND$Companion;Lspace/kscience/kmath/nd/Strides;Lspace/kscience/kmath/structures/BufferFactory;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/kmath/nd/BufferND;
-	public final fun buffered-bYNkpeI ([ILspace/kscience/kmath/structures/BufferFactory;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/BufferND;
-	public static synthetic fun buffered-bYNkpeI$default (Lspace/kscience/kmath/nd/StructureND$Companion;[ILspace/kscience/kmath/structures/BufferFactory;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/kmath/nd/BufferND;
 	public final fun contentEquals (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Z
 	public final fun contentEquals (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;D)Z
 	public static synthetic fun contentEquals$default (Lspace/kscience/kmath/nd/StructureND$Companion;Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;DILjava/lang/Object;)Z
@@ -1419,6 +1484,9 @@ public final class space/kscience/kmath/nd/StructureND$Companion {
 }
 
 public final class space/kscience/kmath/nd/StructureNDKt {
+	public static final fun BufferND--rwW0uw (Lkotlin/reflect/KType;Lspace/kscience/kmath/nd/Strides;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/BufferND;
+	public static final fun BufferND--rwW0uw (Lkotlin/reflect/KType;[ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/BufferND;
+	public static final fun BufferND-vHyE91E (Lkotlin/reflect/KType;[ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/BufferND;
 	public static final fun contentEquals (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Z
 	public static final fun contentEquals (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Comparable;)Z
 	public static final fun contentEquals (Lspace/kscience/kmath/nd/AlgebraND;Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Z
@@ -1449,12 +1517,13 @@ public abstract interface class space/kscience/kmath/nd/WithShape {
 	public abstract fun getShape-IIYLAfE ()[I
 }
 
-public abstract interface class space/kscience/kmath/operations/Algebra {
+public abstract interface class space/kscience/kmath/operations/Algebra : space/kscience/attributes/WithType {
 	public fun binaryOperation (Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
 	public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2;
 	public fun bindSymbol (Ljava/lang/String;)Ljava/lang/Object;
 	public fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object;
-	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
+	public abstract fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
+	public fun getType-V0oMfBY ()Lkotlin/reflect/KType;
 	public fun unaryOperation (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
 	public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1;
 }
@@ -1520,6 +1589,7 @@ public final class space/kscience/kmath/operations/BigIntField : space/kscience/
 	public fun add (Lspace/kscience/kmath/operations/BigInt;Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt;
 	public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
 	public fun divide (Lspace/kscience/kmath/operations/BigInt;Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
 	public synthetic fun getOne ()Ljava/lang/Object;
 	public fun getOne ()Lspace/kscience/kmath/operations/BigInt;
 	public synthetic fun getZero ()Ljava/lang/Object;
@@ -1553,8 +1623,9 @@ public final class space/kscience/kmath/operations/BigIntKt {
 public abstract interface class space/kscience/kmath/operations/BufferAlgebra : space/kscience/kmath/operations/Algebra {
 	public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2;
 	public fun buffer (I[Ljava/lang/Object;)Lspace/kscience/kmath/structures/Buffer;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
 	public abstract fun getElementAlgebra ()Lspace/kscience/kmath/operations/Algebra;
-	public fun getElementBufferFactory ()Lspace/kscience/kmath/structures/BufferFactory;
+	public fun getElementBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
 	public fun map (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/structures/Buffer;
 	public fun mapIndexed (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/structures/Buffer;
 	public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1;
@@ -1568,15 +1639,15 @@ public final class space/kscience/kmath/operations/BufferAlgebraKt {
 	public static final fun asinh (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
 	public static final fun atan (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
 	public static final fun atanh (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
-	public static final fun buffer (Lspace/kscience/kmath/operations/BufferAlgebra;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer;
-	public static final fun buffer (Lspace/kscience/kmath/operations/BufferAlgebra;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer;
+	public static final fun buffer (Lspace/kscience/kmath/operations/BufferAlgebra;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableBuffer;
+	public static final fun buffer (Lspace/kscience/kmath/operations/BufferAlgebra;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableBuffer;
 	public static final fun buffer (Lspace/kscience/kmath/operations/BufferField;[Ljava/lang/Number;)Lspace/kscience/kmath/structures/Buffer;
 	public static final fun cos (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
 	public static final fun cosh (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
 	public static final fun exp (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
 	public static final fun getBufferAlgebra (Lspace/kscience/kmath/operations/Field;)Lspace/kscience/kmath/operations/BufferFieldOps;
-	public static final fun getBufferAlgebra (Lspace/kscience/kmath/operations/IntRing;)Lspace/kscience/kmath/operations/BufferRingOps;
-	public static final fun getBufferAlgebra (Lspace/kscience/kmath/operations/ShortRing;)Lspace/kscience/kmath/operations/BufferRingOps;
+	public static final fun getBufferAlgebra (Lspace/kscience/kmath/operations/Int16Ring;)Lspace/kscience/kmath/operations/BufferRingOps;
+	public static final fun getBufferAlgebra (Lspace/kscience/kmath/operations/Int32Ring;)Lspace/kscience/kmath/operations/BufferRingOps;
 	public static final fun ln (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
 	public static final fun pow (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Number;)Lspace/kscience/kmath/structures/Buffer;
 	public static final fun sin (Lspace/kscience/kmath/operations/BufferAlgebra;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
@@ -1635,201 +1706,6 @@ public abstract interface class space/kscience/kmath/operations/BufferTransform
 	public abstract fun transform (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
 }
 
-public final class space/kscience/kmath/operations/ByteRing : space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/Ring {
-	public static final field INSTANCE Lspace/kscience/kmath/operations/ByteRing;
-	public fun add (BB)Ljava/lang/Byte;
-	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
-	public fun getOne ()Ljava/lang/Byte;
-	public synthetic fun getOne ()Ljava/lang/Object;
-	public fun getZero ()Ljava/lang/Byte;
-	public synthetic fun getZero ()Ljava/lang/Object;
-	public fun minus (BB)Ljava/lang/Byte;
-	public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun multiply (BB)Ljava/lang/Byte;
-	public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun norm (B)Ljava/lang/Byte;
-	public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun number (Ljava/lang/Number;)Ljava/lang/Byte;
-	public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
-	public fun plus (BB)Ljava/lang/Byte;
-	public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun times (BB)Ljava/lang/Byte;
-	public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun unaryMinus (B)Ljava/lang/Byte;
-	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
-}
-
-public final class space/kscience/kmath/operations/DoubleBufferField : space/kscience/kmath/operations/DoubleBufferOps, space/kscience/kmath/operations/ExtendedField {
-	public fun <init> (I)V
-	public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun acosh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun asinh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun atanh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun cosh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun getOne ()Ljava/lang/Object;
-	public fun getOne ()Lspace/kscience/kmath/structures/Buffer;
-	public final fun getSize ()I
-	public synthetic fun getZero ()Ljava/lang/Object;
-	public fun getZero ()Lspace/kscience/kmath/structures/Buffer;
-	public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
-	public synthetic fun power (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Number;)Lspace/kscience/kmath/structures/Buffer;
-	public fun power-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Number;)[D
-	public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun sinh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun tanh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1;
-}
-
-public abstract class space/kscience/kmath/operations/DoubleBufferOps : space/kscience/kmath/operations/BufferAlgebra, space/kscience/kmath/operations/ExtendedFieldOps, space/kscience/kmath/operations/Norm {
-	public static final field Companion Lspace/kscience/kmath/operations/DoubleBufferOps$Companion;
-	public fun <init> ()V
-	public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun acos-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun acosh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun add-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun asin-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun asinh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun atan-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun atanh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2;
-	public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun cos-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun cosh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun divide-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun exp-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun getElementAlgebra ()Lspace/kscience/kmath/operations/Algebra;
-	public fun getElementAlgebra ()Lspace/kscience/kmath/operations/DoubleField;
-	public synthetic fun getElementBufferFactory ()Lspace/kscience/kmath/structures/BufferFactory;
-	public fun getElementBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
-	public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun ln-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun map (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/structures/Buffer;
-	public final fun map-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function2;)[D
-	public synthetic fun mapIndexed (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/structures/Buffer;
-	public final fun mapIndexed-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function3;)[D
-	public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun minus-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun norm (Lspace/kscience/kmath/structures/Buffer;)Ljava/lang/Double;
-	public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun plus-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
-	public fun power (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Number;)Lspace/kscience/kmath/structures/Buffer;
-	public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object;
-	public fun scale-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;D)[D
-	public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun sin-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun sinh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun tan-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun tanh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun unaryMinus-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-	public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1;
-	public synthetic fun zip (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/structures/Buffer;
-	public final fun zip-XquIszc (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function3;)[D
-}
-
-public final class space/kscience/kmath/operations/DoubleBufferOps$Companion : space/kscience/kmath/operations/DoubleBufferOps {
-}
-
-public final class space/kscience/kmath/operations/DoubleBufferOpsKt {
-	public static final fun average (Lspace/kscience/kmath/operations/DoubleBufferOps;Lspace/kscience/kmath/structures/Buffer;)D
-	public static final fun averageOf (Lspace/kscience/kmath/operations/DoubleBufferOps;Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function1;)D
-	public static final fun covariance (Lspace/kscience/kmath/operations/DoubleBufferOps;Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)D
-	public static final fun dispersion (Lspace/kscience/kmath/operations/DoubleBufferOps;Lspace/kscience/kmath/structures/Buffer;)D
-	public static final fun std (Lspace/kscience/kmath/operations/DoubleBufferOps;Lspace/kscience/kmath/structures/Buffer;)D
-	public static final fun sum (Lspace/kscience/kmath/operations/DoubleBufferOps;Lspace/kscience/kmath/structures/Buffer;)D
-	public static final fun sumOf (Lspace/kscience/kmath/operations/DoubleBufferOps;Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function1;)D
-}
-
-public final class space/kscience/kmath/operations/DoubleField : space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/ScaleOperations {
-	public static final field INSTANCE Lspace/kscience/kmath/operations/DoubleField;
-	public fun acos (D)Ljava/lang/Double;
-	public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun acosh (D)Ljava/lang/Double;
-	public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun add (DD)Ljava/lang/Double;
-	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun asin (D)Ljava/lang/Double;
-	public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun asinh (D)Ljava/lang/Double;
-	public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun atan (D)Ljava/lang/Double;
-	public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun atanh (D)Ljava/lang/Double;
-	public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2;
-	public fun cos (D)Ljava/lang/Double;
-	public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun cosh (D)Ljava/lang/Double;
-	public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun div (DD)Ljava/lang/Double;
-	public synthetic fun div (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun divide (DD)Ljava/lang/Double;
-	public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun exp (D)Ljava/lang/Double;
-	public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
-	public fun getOne ()Ljava/lang/Double;
-	public synthetic fun getOne ()Ljava/lang/Object;
-	public fun getZero ()Ljava/lang/Double;
-	public synthetic fun getZero ()Ljava/lang/Object;
-	public fun ln (D)Ljava/lang/Double;
-	public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun minus (DD)Ljava/lang/Double;
-	public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun multiply (DD)Ljava/lang/Double;
-	public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun norm (D)Ljava/lang/Double;
-	public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun number (Ljava/lang/Number;)Ljava/lang/Double;
-	public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
-	public fun plus (DD)Ljava/lang/Double;
-	public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun power (DLjava/lang/Number;)Ljava/lang/Double;
-	public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
-	public fun scale (DD)Ljava/lang/Double;
-	public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object;
-	public fun sin (D)Ljava/lang/Double;
-	public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun sinh (D)Ljava/lang/Double;
-	public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun sqrt (D)Ljava/lang/Double;
-	public synthetic fun sqrt (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun tan (D)Ljava/lang/Double;
-	public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun tanh (D)Ljava/lang/Double;
-	public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun times (DD)Ljava/lang/Double;
-	public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun unaryMinus (D)Ljava/lang/Double;
-	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
-}
-
-public final class space/kscience/kmath/operations/DoubleL2Norm : space/kscience/kmath/operations/Norm {
-	public static final field INSTANCE Lspace/kscience/kmath/operations/DoubleL2Norm;
-	public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun norm (Lspace/kscience/kmath/structures/Buffer;)Ljava/lang/Double;
-}
-
 public abstract interface class space/kscience/kmath/operations/ExponentialOperations : space/kscience/kmath/operations/Algebra {
 	public static final field ACOSH_OPERATION Ljava/lang/String;
 	public static final field ASINH_OPERATION Ljava/lang/String;
@@ -1899,8 +1775,8 @@ public final class space/kscience/kmath/operations/FieldOps$Companion {
 	public static final field DIV_OPERATION Ljava/lang/String;
 }
 
-public final class space/kscience/kmath/operations/FloatField : space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/Norm {
-	public static final field INSTANCE Lspace/kscience/kmath/operations/FloatField;
+public final class space/kscience/kmath/operations/Float32Field : space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/Norm {
+	public static final field INSTANCE Lspace/kscience/kmath/operations/Float32Field;
 	public fun acos (F)Ljava/lang/Float;
 	public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object;
 	public fun acosh (F)Ljava/lang/Float;
@@ -1963,6 +1839,175 @@ public final class space/kscience/kmath/operations/FloatField : space/kscience/k
 	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
 }
 
+public final class space/kscience/kmath/operations/Float64BufferField : space/kscience/kmath/operations/Float64BufferOps, space/kscience/kmath/operations/ExtendedField {
+	public fun <init> (I)V
+	public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun acosh-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun asinh-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun atanh-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun cosh-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun getOne ()Ljava/lang/Object;
+	public fun getOne ()Lspace/kscience/kmath/structures/Buffer;
+	public final fun getSize ()I
+	public synthetic fun getZero ()Ljava/lang/Object;
+	public fun getZero ()Lspace/kscience/kmath/structures/Buffer;
+	public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
+	public synthetic fun power (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Number;)Lspace/kscience/kmath/structures/Buffer;
+	public fun power-Vq5tpWc (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Number;)[D
+	public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun sinh-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun tanh-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1;
+}
+
+public abstract class space/kscience/kmath/operations/Float64BufferOps : space/kscience/kmath/operations/BufferAlgebra, space/kscience/kmath/operations/ExtendedFieldOps, space/kscience/kmath/operations/Norm {
+	public static final field Companion Lspace/kscience/kmath/operations/Float64BufferOps$Companion;
+	public fun <init> ()V
+	public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun acos-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun acosh-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun add-Vq5tpWc (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun asin-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun asinh-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun atan-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun atanh-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2;
+	public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun cos-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun cosh-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun divide-Vq5tpWc (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun exp-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun getElementAlgebra ()Lspace/kscience/kmath/operations/Algebra;
+	public fun getElementAlgebra ()Lspace/kscience/kmath/operations/Float64Field;
+	public fun getElementBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
+	public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun ln-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun map (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/structures/Buffer;
+	public final fun map-Vq5tpWc (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function2;)[D
+	public synthetic fun mapIndexed (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/structures/Buffer;
+	public final fun mapIndexed-Vq5tpWc (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function3;)[D
+	public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun minus-Vq5tpWc (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun norm (Lspace/kscience/kmath/structures/Buffer;)Ljava/lang/Double;
+	public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun plus-Vq5tpWc (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
+	public fun power (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Number;)Lspace/kscience/kmath/structures/Buffer;
+	public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object;
+	public fun scale-Vq5tpWc (Lspace/kscience/kmath/structures/Buffer;D)[D
+	public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun sin-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun sinh-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun tan-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun tanh-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun unaryMinus-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
+	public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1;
+	public synthetic fun zip (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/structures/Buffer;
+	public final fun zip-Qj2idzA (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function3;)[D
+}
+
+public final class space/kscience/kmath/operations/Float64BufferOps$Companion : space/kscience/kmath/operations/Float64BufferOps {
+}
+
+public final class space/kscience/kmath/operations/Float64BufferOpsKt {
+	public static final fun average (Lspace/kscience/kmath/operations/Float64BufferOps;Lspace/kscience/kmath/structures/Buffer;)D
+	public static final fun averageOf (Lspace/kscience/kmath/operations/Float64BufferOps;Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function1;)D
+	public static final fun covariance (Lspace/kscience/kmath/operations/Float64BufferOps;Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)D
+	public static final fun dispersion (Lspace/kscience/kmath/operations/Float64BufferOps;Lspace/kscience/kmath/structures/Buffer;)D
+	public static final fun std (Lspace/kscience/kmath/operations/Float64BufferOps;Lspace/kscience/kmath/structures/Buffer;)D
+	public static final fun sum (Lspace/kscience/kmath/operations/Float64BufferOps;Lspace/kscience/kmath/structures/Buffer;)D
+	public static final fun sumOf (Lspace/kscience/kmath/operations/Float64BufferOps;Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function1;)D
+}
+
+public final class space/kscience/kmath/operations/Float64Field : space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/ScaleOperations {
+	public static final field INSTANCE Lspace/kscience/kmath/operations/Float64Field;
+	public fun acos (D)Ljava/lang/Double;
+	public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun acosh (D)Ljava/lang/Double;
+	public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun add (DD)Ljava/lang/Double;
+	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun asin (D)Ljava/lang/Double;
+	public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun asinh (D)Ljava/lang/Double;
+	public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun atan (D)Ljava/lang/Double;
+	public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun atanh (D)Ljava/lang/Double;
+	public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2;
+	public fun cos (D)Ljava/lang/Double;
+	public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun cosh (D)Ljava/lang/Double;
+	public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun div (DD)Ljava/lang/Double;
+	public synthetic fun div (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun divide (DD)Ljava/lang/Double;
+	public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun exp (D)Ljava/lang/Double;
+	public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
+	public fun getOne ()Ljava/lang/Double;
+	public synthetic fun getOne ()Ljava/lang/Object;
+	public fun getZero ()Ljava/lang/Double;
+	public synthetic fun getZero ()Ljava/lang/Object;
+	public fun ln (D)Ljava/lang/Double;
+	public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun minus (DD)Ljava/lang/Double;
+	public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun multiply (DD)Ljava/lang/Double;
+	public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun norm (D)Ljava/lang/Double;
+	public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun number (Ljava/lang/Number;)Ljava/lang/Double;
+	public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
+	public fun plus (DD)Ljava/lang/Double;
+	public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun power (DLjava/lang/Number;)Ljava/lang/Double;
+	public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
+	public fun scale (DD)Ljava/lang/Double;
+	public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object;
+	public fun sin (D)Ljava/lang/Double;
+	public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun sinh (D)Ljava/lang/Double;
+	public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun sqrt (D)Ljava/lang/Double;
+	public synthetic fun sqrt (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun tan (D)Ljava/lang/Double;
+	public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun tanh (D)Ljava/lang/Double;
+	public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun times (DD)Ljava/lang/Double;
+	public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun unaryMinus (D)Ljava/lang/Double;
+	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
+}
+
+public final class space/kscience/kmath/operations/Float64L2Norm : space/kscience/kmath/operations/Norm {
+	public static final field INSTANCE Lspace/kscience/kmath/operations/Float64L2Norm;
+	public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun norm (Lspace/kscience/kmath/structures/Buffer;)Ljava/lang/Double;
+}
+
 public abstract interface class space/kscience/kmath/operations/Group : space/kscience/kmath/operations/GroupOps {
 	public abstract fun getZero ()Ljava/lang/Object;
 }
@@ -1985,8 +2030,79 @@ public final class space/kscience/kmath/operations/GroupOps$Companion {
 	public static final field PLUS_OPERATION Ljava/lang/String;
 }
 
-public final class space/kscience/kmath/operations/IntRing : space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/Ring {
-	public static final field INSTANCE Lspace/kscience/kmath/operations/IntRing;
+public final class space/kscience/kmath/operations/Int16Field : space/kscience/kmath/operations/Field, space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/NumericAlgebra {
+	public static final field INSTANCE Lspace/kscience/kmath/operations/Int16Field;
+	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun add (SS)Ljava/lang/Short;
+	public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun divide (SS)Ljava/lang/Short;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
+	public synthetic fun getOne ()Ljava/lang/Object;
+	public fun getOne ()Ljava/lang/Short;
+	public synthetic fun getZero ()Ljava/lang/Object;
+	public fun getZero ()Ljava/lang/Short;
+	public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun multiply (SS)Ljava/lang/Short;
+	public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun norm (S)Ljava/lang/Short;
+	public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
+	public fun number (Ljava/lang/Number;)Ljava/lang/Short;
+	public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object;
+	public fun scale (SD)Ljava/lang/Short;
+	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun unaryMinus (S)Ljava/lang/Short;
+}
+
+public final class space/kscience/kmath/operations/Int16Ring : space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/Ring {
+	public static final field INSTANCE Lspace/kscience/kmath/operations/Int16Ring;
+	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun add (SS)Ljava/lang/Short;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
+	public synthetic fun getOne ()Ljava/lang/Object;
+	public fun getOne ()Ljava/lang/Short;
+	public synthetic fun getZero ()Ljava/lang/Object;
+	public fun getZero ()Ljava/lang/Short;
+	public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun minus (SS)Ljava/lang/Short;
+	public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun multiply (SS)Ljava/lang/Short;
+	public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun norm (S)Ljava/lang/Short;
+	public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
+	public fun number (Ljava/lang/Number;)Ljava/lang/Short;
+	public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun plus (SS)Ljava/lang/Short;
+	public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun times (SS)Ljava/lang/Short;
+	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun unaryMinus (S)Ljava/lang/Short;
+}
+
+public final class space/kscience/kmath/operations/Int32Field : space/kscience/kmath/operations/Field, space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/NumericAlgebra {
+	public static final field INSTANCE Lspace/kscience/kmath/operations/Int32Field;
+	public fun add (II)Ljava/lang/Integer;
+	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun divide (II)Ljava/lang/Integer;
+	public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
+	public fun getOne ()Ljava/lang/Integer;
+	public synthetic fun getOne ()Ljava/lang/Object;
+	public fun getZero ()Ljava/lang/Integer;
+	public synthetic fun getZero ()Ljava/lang/Object;
+	public fun multiply (II)Ljava/lang/Integer;
+	public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun norm (I)Ljava/lang/Integer;
+	public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun number (Ljava/lang/Number;)Ljava/lang/Integer;
+	public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
+	public fun scale (ID)Ljava/lang/Integer;
+	public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object;
+	public fun unaryMinus (I)Ljava/lang/Integer;
+	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
+}
+
+public final class space/kscience/kmath/operations/Int32Ring : space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/Ring {
+	public static final field INSTANCE Lspace/kscience/kmath/operations/Int32Ring;
 	public fun add (II)Ljava/lang/Integer;
 	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
 	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
@@ -2010,6 +2126,79 @@ public final class space/kscience/kmath/operations/IntRing : space/kscience/kmat
 	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
 }
 
+public final class space/kscience/kmath/operations/Int64Field : space/kscience/kmath/operations/Field, space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/NumericAlgebra {
+	public static final field INSTANCE Lspace/kscience/kmath/operations/Int64Field;
+	public fun add (JJ)Ljava/lang/Long;
+	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun divide (JJ)Ljava/lang/Long;
+	public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
+	public fun getOne ()Ljava/lang/Long;
+	public synthetic fun getOne ()Ljava/lang/Object;
+	public fun getZero ()Ljava/lang/Long;
+	public synthetic fun getZero ()Ljava/lang/Object;
+	public fun multiply (JJ)Ljava/lang/Long;
+	public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun norm (J)Ljava/lang/Long;
+	public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun number (Ljava/lang/Number;)Ljava/lang/Long;
+	public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
+	public fun scale (JD)Ljava/lang/Long;
+	public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object;
+	public fun unaryMinus (J)Ljava/lang/Long;
+	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
+}
+
+public final class space/kscience/kmath/operations/Int64Ring : space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/Ring {
+	public static final field INSTANCE Lspace/kscience/kmath/operations/Int64Ring;
+	public fun add (JJ)Ljava/lang/Long;
+	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
+	public fun getOne ()Ljava/lang/Long;
+	public synthetic fun getOne ()Ljava/lang/Object;
+	public fun getZero ()Ljava/lang/Long;
+	public synthetic fun getZero ()Ljava/lang/Object;
+	public fun minus (JJ)Ljava/lang/Long;
+	public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun multiply (JJ)Ljava/lang/Long;
+	public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun norm (J)Ljava/lang/Long;
+	public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun number (Ljava/lang/Number;)Ljava/lang/Long;
+	public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
+	public fun plus (JJ)Ljava/lang/Long;
+	public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun times (JJ)Ljava/lang/Long;
+	public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun unaryMinus (J)Ljava/lang/Long;
+	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
+}
+
+public final class space/kscience/kmath/operations/Int8Ring : space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/Ring {
+	public static final field INSTANCE Lspace/kscience/kmath/operations/Int8Ring;
+	public fun add (BB)Ljava/lang/Byte;
+	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
+	public fun getOne ()Ljava/lang/Byte;
+	public synthetic fun getOne ()Ljava/lang/Object;
+	public fun getZero ()Ljava/lang/Byte;
+	public synthetic fun getZero ()Ljava/lang/Object;
+	public fun minus (BB)Ljava/lang/Byte;
+	public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun multiply (BB)Ljava/lang/Byte;
+	public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun norm (B)Ljava/lang/Byte;
+	public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun number (Ljava/lang/Number;)Ljava/lang/Byte;
+	public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
+	public fun plus (BB)Ljava/lang/Byte;
+	public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun times (BB)Ljava/lang/Byte;
+	public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun unaryMinus (B)Ljava/lang/Byte;
+	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
+}
+
 public final class space/kscience/kmath/operations/IsIntegerKt {
 	public static final fun isInteger (Ljava/lang/Number;)Z
 }
@@ -2030,6 +2219,7 @@ public abstract class space/kscience/kmath/operations/JBigDecimalFieldBase : spa
 	public fun add (Ljava/math/BigDecimal;Ljava/math/BigDecimal;)Ljava/math/BigDecimal;
 	public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
 	public fun divide (Ljava/math/BigDecimal;Ljava/math/BigDecimal;)Ljava/math/BigDecimal;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
 	public synthetic fun getOne ()Ljava/lang/Object;
 	public fun getOne ()Ljava/math/BigDecimal;
 	public synthetic fun getZero ()Ljava/lang/Object;
@@ -2054,6 +2244,7 @@ public final class space/kscience/kmath/operations/JBigIntegerField : space/ksci
 	public static final field INSTANCE Lspace/kscience/kmath/operations/JBigIntegerField;
 	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
 	public fun add (Ljava/math/BigInteger;Ljava/math/BigInteger;)Ljava/math/BigInteger;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
 	public synthetic fun getOne ()Ljava/lang/Object;
 	public fun getOne ()Ljava/math/BigInteger;
 	public synthetic fun getZero ()Ljava/lang/Object;
@@ -2073,42 +2264,17 @@ public final class space/kscience/kmath/operations/LogicAlgebra$Companion {
 	public final fun getTRUE ()Lspace/kscience/kmath/expressions/Symbol;
 }
 
-public final class space/kscience/kmath/operations/LongRing : space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/Ring {
-	public static final field INSTANCE Lspace/kscience/kmath/operations/LongRing;
-	public fun add (JJ)Ljava/lang/Long;
-	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
-	public fun getOne ()Ljava/lang/Long;
-	public synthetic fun getOne ()Ljava/lang/Object;
-	public fun getZero ()Ljava/lang/Long;
-	public synthetic fun getZero ()Ljava/lang/Object;
-	public fun minus (JJ)Ljava/lang/Long;
-	public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun multiply (JJ)Ljava/lang/Long;
-	public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun norm (J)Ljava/lang/Long;
-	public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun number (Ljava/lang/Number;)Ljava/lang/Long;
-	public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
-	public fun plus (JJ)Ljava/lang/Long;
-	public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun times (JJ)Ljava/lang/Long;
-	public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun unaryMinus (J)Ljava/lang/Long;
-	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
-}
-
 public abstract interface class space/kscience/kmath/operations/Norm {
 	public abstract fun norm (Ljava/lang/Object;)Ljava/lang/Object;
 }
 
 public final class space/kscience/kmath/operations/NumbersKt {
-	public static final fun getAlgebra (Lkotlin/jvm/internal/ByteCompanionObject;)Lspace/kscience/kmath/operations/ByteRing;
-	public static final fun getAlgebra (Lkotlin/jvm/internal/DoubleCompanionObject;)Lspace/kscience/kmath/operations/DoubleField;
-	public static final fun getAlgebra (Lkotlin/jvm/internal/FloatCompanionObject;)Lspace/kscience/kmath/operations/FloatField;
-	public static final fun getAlgebra (Lkotlin/jvm/internal/IntCompanionObject;)Lspace/kscience/kmath/operations/IntRing;
-	public static final fun getAlgebra (Lkotlin/jvm/internal/LongCompanionObject;)Lspace/kscience/kmath/operations/LongRing;
-	public static final fun getAlgebra (Lkotlin/jvm/internal/ShortCompanionObject;)Lspace/kscience/kmath/operations/ShortRing;
+	public static final fun getAlgebra (Lkotlin/jvm/internal/ByteCompanionObject;)Lspace/kscience/kmath/operations/Int8Ring;
+	public static final fun getAlgebra (Lkotlin/jvm/internal/DoubleCompanionObject;)Lspace/kscience/kmath/operations/Float64Field;
+	public static final fun getAlgebra (Lkotlin/jvm/internal/FloatCompanionObject;)Lspace/kscience/kmath/operations/Float32Field;
+	public static final fun getAlgebra (Lkotlin/jvm/internal/IntCompanionObject;)Lspace/kscience/kmath/operations/Int32Ring;
+	public static final fun getAlgebra (Lkotlin/jvm/internal/LongCompanionObject;)Lspace/kscience/kmath/operations/Int64Ring;
+	public static final fun getAlgebra (Lkotlin/jvm/internal/ShortCompanionObject;)Lspace/kscience/kmath/operations/Int16Ring;
 }
 
 public abstract interface class space/kscience/kmath/operations/NumericAlgebra : space/kscience/kmath/operations/Algebra {
@@ -2125,7 +2291,7 @@ public final class space/kscience/kmath/operations/NumericAlgebraKt {
 	public static final fun getPi (Lspace/kscience/kmath/operations/NumericAlgebra;)Ljava/lang/Object;
 }
 
-public abstract interface class space/kscience/kmath/operations/PowerOperations : space/kscience/kmath/operations/FieldOps {
+public abstract interface class space/kscience/kmath/operations/PowerOperations : space/kscience/kmath/operations/Algebra {
 	public static final field Companion Lspace/kscience/kmath/operations/PowerOperations$Companion;
 	public static final field POW_OPERATION Ljava/lang/String;
 	public static final field SQRT_OPERATION Ljava/lang/String;
@@ -2167,31 +2333,6 @@ public abstract interface class space/kscience/kmath/operations/ScaleOperations
 	public fun times (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
 }
 
-public final class space/kscience/kmath/operations/ShortRing : space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/Ring {
-	public static final field INSTANCE Lspace/kscience/kmath/operations/ShortRing;
-	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun add (SS)Ljava/lang/Short;
-	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
-	public synthetic fun getOne ()Ljava/lang/Object;
-	public fun getOne ()Ljava/lang/Short;
-	public synthetic fun getZero ()Ljava/lang/Object;
-	public fun getZero ()Ljava/lang/Short;
-	public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun minus (SS)Ljava/lang/Short;
-	public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun multiply (SS)Ljava/lang/Short;
-	public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun norm (S)Ljava/lang/Short;
-	public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
-	public fun number (Ljava/lang/Number;)Ljava/lang/Short;
-	public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun plus (SS)Ljava/lang/Short;
-	public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-	public fun times (SS)Ljava/lang/Short;
-	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
-	public fun unaryMinus (S)Ljava/lang/Short;
-}
-
 public abstract interface class space/kscience/kmath/operations/TrigonometricOperations : space/kscience/kmath/operations/Algebra {
 	public static final field ACOS_OPERATION Ljava/lang/String;
 	public static final field ASIN_OPERATION Ljava/lang/String;
@@ -2222,17 +2363,28 @@ public abstract interface class space/kscience/kmath/operations/WithSize {
 }
 
 public final class space/kscience/kmath/structures/ArrayBuffer : space/kscience/kmath/structures/MutableBuffer {
-	public fun <init> ([Ljava/lang/Object;)V
-	public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer;
+	public static final synthetic fun box-impl ([Ljava/lang/Object;)Lspace/kscience/kmath/structures/ArrayBuffer;
+	public static fun constructor-impl ([Ljava/lang/Object;)[Ljava/lang/Object;
+	public fun equals (Ljava/lang/Object;)Z
+	public static fun equals-impl ([Ljava/lang/Object;Ljava/lang/Object;)Z
+	public static final fun equals-impl0 ([Ljava/lang/Object;[Ljava/lang/Object;)Z
 	public fun get (I)Ljava/lang/Object;
+	public static fun get-impl ([Ljava/lang/Object;I)Ljava/lang/Object;
 	public fun getSize ()I
+	public static fun getSize-impl ([Ljava/lang/Object;)I
+	public fun hashCode ()I
+	public static fun hashCode-impl ([Ljava/lang/Object;)I
 	public fun iterator ()Ljava/util/Iterator;
+	public static fun iterator-impl ([Ljava/lang/Object;)Ljava/util/Iterator;
 	public fun set (ILjava/lang/Object;)V
+	public static fun set-impl ([Ljava/lang/Object;ILjava/lang/Object;)V
 	public fun toString ()Ljava/lang/String;
+	public static fun toString-impl ([Ljava/lang/Object;)Ljava/lang/String;
+	public final synthetic fun unbox-impl ()[Ljava/lang/Object;
 }
 
 public final class space/kscience/kmath/structures/ArrayBufferKt {
-	public static final fun asBuffer ([Ljava/lang/Object;)Lspace/kscience/kmath/structures/ArrayBuffer;
+	public static final fun asBuffer ([Ljava/lang/Object;)[Ljava/lang/Object;
 }
 
 public abstract interface class space/kscience/kmath/structures/Buffer : space/kscience/kmath/operations/WithSize {
@@ -2244,8 +2396,6 @@ public abstract interface class space/kscience/kmath/structures/Buffer : space/k
 }
 
 public final class space/kscience/kmath/structures/Buffer$Companion {
-	public final fun auto (Lkotlin/reflect/KClass;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer;
-	public final fun boxing (ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer;
 	public final fun contentEquals (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)Z
 	public final fun toString (Lspace/kscience/kmath/structures/Buffer;)Ljava/lang/String;
 }
@@ -2260,17 +2410,14 @@ public final class space/kscience/kmath/structures/BufferExpanded : space/kscien
 	public fun toString ()Ljava/lang/String;
 }
 
-public abstract interface class space/kscience/kmath/structures/BufferFactory {
-	public static final field Companion Lspace/kscience/kmath/structures/BufferFactory$Companion;
+public abstract interface class space/kscience/kmath/structures/BufferFactory : space/kscience/attributes/WithType {
 	public abstract fun invoke (ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer;
 }
 
-public final class space/kscience/kmath/structures/BufferFactory$Companion {
-	public final fun boxing ()Lspace/kscience/kmath/structures/BufferFactory;
-}
-
 public final class space/kscience/kmath/structures/BufferKt {
-	public static final fun asReadOnly (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
+	public static final fun Buffer--rwW0uw (Lkotlin/reflect/KType;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer;
+	public static final fun BufferFactory-X0YbwmU (Lkotlin/reflect/KType;)Lspace/kscience/kmath/structures/BufferFactory;
+	public static final fun MutableBufferFactory-X0YbwmU (Lkotlin/reflect/KType;)Lspace/kscience/kmath/structures/MutableBufferFactory;
 	public static final fun first (Lspace/kscience/kmath/structures/Buffer;)Ljava/lang/Object;
 	public static final fun get-Qn1smSk (Lspace/kscience/kmath/structures/Buffer;I)Ljava/lang/Object;
 	public static final fun getIndices (Lspace/kscience/kmath/structures/Buffer;)Lkotlin/ranges/IntRange;
@@ -2278,6 +2425,10 @@ public final class space/kscience/kmath/structures/BufferKt {
 	public static final fun last (Lspace/kscience/kmath/structures/Buffer;)Ljava/lang/Object;
 }
 
+public final class space/kscience/kmath/structures/BufferListKt {
+	public static final fun asList (Lspace/kscience/kmath/structures/Buffer;)Ljava/util/List;
+}
+
 public final class space/kscience/kmath/structures/BufferPrimitiveAccessKt {
 }
 
@@ -2304,87 +2455,6 @@ public final class space/kscience/kmath/structures/BufferViewKt {
 	public static final fun slice (Lspace/kscience/kmath/structures/Buffer;Lkotlin/ranges/IntRange;)Lspace/kscience/kmath/structures/BufferView;
 }
 
-public final class space/kscience/kmath/structures/ByteBuffer : space/kscience/kmath/structures/MutableBuffer {
-	public static final synthetic fun box-impl ([B)Lspace/kscience/kmath/structures/ByteBuffer;
-	public static fun constructor-impl ([B)[B
-	public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer;
-	public static fun copy-impl ([B)Lspace/kscience/kmath/structures/MutableBuffer;
-	public fun equals (Ljava/lang/Object;)Z
-	public static fun equals-impl ([BLjava/lang/Object;)Z
-	public static final fun equals-impl0 ([B[B)Z
-	public fun get (I)Ljava/lang/Byte;
-	public synthetic fun get (I)Ljava/lang/Object;
-	public static fun get-impl ([BI)Ljava/lang/Byte;
-	public final fun getArray ()[B
-	public fun getSize ()I
-	public static fun getSize-impl ([B)I
-	public fun hashCode ()I
-	public static fun hashCode-impl ([B)I
-	public synthetic fun iterator ()Ljava/util/Iterator;
-	public fun iterator ()Lkotlin/collections/ByteIterator;
-	public static fun iterator-impl ([B)Lkotlin/collections/ByteIterator;
-	public fun set (IB)V
-	public synthetic fun set (ILjava/lang/Object;)V
-	public static fun set-impl ([BIB)V
-	public fun toString ()Ljava/lang/String;
-	public static fun toString-impl ([B)Ljava/lang/String;
-	public final synthetic fun unbox-impl ()[B
-}
-
-public final class space/kscience/kmath/structures/ByteBufferKt {
-	public static final fun ByteBuffer (ILkotlin/jvm/functions/Function1;)[B
-	public static final fun ByteBuffer ([B)[B
-	public static final fun asBuffer ([B)[B
-	public static final fun toByteArray (Lspace/kscience/kmath/structures/Buffer;)[B
-}
-
-public final class space/kscience/kmath/structures/DoubleBuffer : space/kscience/kmath/structures/PrimitiveBuffer {
-	public static final field Companion Lspace/kscience/kmath/structures/DoubleBuffer$Companion;
-	public static final synthetic fun box-impl ([D)Lspace/kscience/kmath/structures/DoubleBuffer;
-	public static fun constructor-impl ([D)[D
-	public synthetic fun copy ()Lspace/kscience/kmath/structures/MutableBuffer;
-	public fun copy-Dv3HvWU ()[D
-	public static fun copy-Dv3HvWU ([D)[D
-	public fun equals (Ljava/lang/Object;)Z
-	public static fun equals-impl ([DLjava/lang/Object;)Z
-	public static final fun equals-impl0 ([D[D)Z
-	public fun get (I)Ljava/lang/Double;
-	public synthetic fun get (I)Ljava/lang/Object;
-	public static fun get-impl ([DI)Ljava/lang/Double;
-	public final fun getArray ()[D
-	public fun getSize ()I
-	public static fun getSize-impl ([D)I
-	public fun hashCode ()I
-	public static fun hashCode-impl ([D)I
-	public synthetic fun iterator ()Ljava/util/Iterator;
-	public fun iterator ()Lkotlin/collections/DoubleIterator;
-	public static fun iterator-impl ([D)Lkotlin/collections/DoubleIterator;
-	public fun set (ID)V
-	public synthetic fun set (ILjava/lang/Object;)V
-	public static fun set-impl ([DID)V
-	public fun toString ()Ljava/lang/String;
-	public static fun toString-impl ([D)Ljava/lang/String;
-	public final synthetic fun unbox-impl ()[D
-}
-
-public final class space/kscience/kmath/structures/DoubleBuffer$Companion {
-	public final fun zero-Udx-57Q (I)[D
-}
-
-public final class space/kscience/kmath/structures/DoubleBufferKt {
-	public static final fun DoubleBuffer (ILkotlin/jvm/functions/Function1;)[D
-	public static final fun DoubleBuffer ([D)[D
-	public static final fun asBuffer ([D)[D
-	public static final fun toDoubleArray (Lspace/kscience/kmath/structures/Buffer;)[D
-	public static final fun toDoubleBuffer (Lspace/kscience/kmath/structures/Buffer;)[D
-}
-
-public abstract interface class space/kscience/kmath/structures/DoubleBufferTransform : space/kscience/kmath/operations/BufferTransform {
-	public synthetic fun transform (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
-	public abstract fun transform-7Zdoou4 ([D)[D
-	public fun transform-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D
-}
-
 public abstract interface class space/kscience/kmath/structures/FlaggedBuffer : space/kscience/kmath/structures/Buffer {
 	public abstract fun getFlag (I)B
 }
@@ -2408,11 +2478,9 @@ public final class space/kscience/kmath/structures/FlaggedDoubleBuffer : space/k
 	public fun toString ()Ljava/lang/String;
 }
 
-public final class space/kscience/kmath/structures/FloatBuffer : space/kscience/kmath/structures/PrimitiveBuffer {
-	public static final synthetic fun box-impl ([F)Lspace/kscience/kmath/structures/FloatBuffer;
+public final class space/kscience/kmath/structures/Float32Buffer : space/kscience/kmath/structures/PrimitiveBuffer {
+	public static final synthetic fun box-impl ([F)Lspace/kscience/kmath/structures/Float32Buffer;
 	public static fun constructor-impl ([F)[F
-	public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer;
-	public static fun copy-impl ([F)Lspace/kscience/kmath/structures/MutableBuffer;
 	public fun equals (Ljava/lang/Object;)Z
 	public static fun equals-impl ([FLjava/lang/Object;)Z
 	public static final fun equals-impl0 ([F[F)Z
@@ -2435,224 +2503,60 @@ public final class space/kscience/kmath/structures/FloatBuffer : space/kscience/
 	public final synthetic fun unbox-impl ()[F
 }
 
-public final class space/kscience/kmath/structures/FloatBufferKt {
-	public static final fun FloatBuffer (ILkotlin/jvm/functions/Function1;)[F
-	public static final fun FloatBuffer ([F)[F
+public final class space/kscience/kmath/structures/Float32BufferKt {
+	public static final fun Float32Buffer (ILkotlin/jvm/functions/Function1;)[F
+	public static final fun Float32Buffer ([F)[F
 	public static final fun asBuffer ([F)[F
 	public static final fun toFloatArray (Lspace/kscience/kmath/structures/Buffer;)[F
 }
 
-public final class space/kscience/kmath/structures/IntBuffer : space/kscience/kmath/structures/PrimitiveBuffer {
-	public static final synthetic fun box-impl ([I)Lspace/kscience/kmath/structures/IntBuffer;
-	public static fun constructor-impl ([I)[I
-	public synthetic fun copy ()Lspace/kscience/kmath/structures/MutableBuffer;
-	public fun copy-ir4F4A8 ()[I
-	public static fun copy-ir4F4A8 ([I)[I
+public final class space/kscience/kmath/structures/Float64Buffer : space/kscience/kmath/structures/PrimitiveBuffer {
+	public static final field Companion Lspace/kscience/kmath/structures/Float64Buffer$Companion;
+	public static final synthetic fun box-impl ([D)Lspace/kscience/kmath/structures/Float64Buffer;
+	public static fun constructor-impl ([D)[D
 	public fun equals (Ljava/lang/Object;)Z
-	public static fun equals-impl ([ILjava/lang/Object;)Z
-	public static final fun equals-impl0 ([I[I)Z
-	public fun get (I)Ljava/lang/Integer;
+	public static fun equals-impl ([DLjava/lang/Object;)Z
+	public static final fun equals-impl0 ([D[D)Z
+	public fun get (I)Ljava/lang/Double;
 	public synthetic fun get (I)Ljava/lang/Object;
-	public static fun get-impl ([II)Ljava/lang/Integer;
-	public final fun getArray ()[I
+	public static fun get-impl ([DI)Ljava/lang/Double;
+	public final fun getArray ()[D
 	public fun getSize ()I
-	public static fun getSize-impl ([I)I
+	public static fun getSize-impl ([D)I
 	public fun hashCode ()I
-	public static fun hashCode-impl ([I)I
+	public static fun hashCode-impl ([D)I
 	public synthetic fun iterator ()Ljava/util/Iterator;
-	public fun iterator ()Lkotlin/collections/IntIterator;
-	public static fun iterator-impl ([I)Lkotlin/collections/IntIterator;
-	public fun set (II)V
+	public fun iterator ()Lkotlin/collections/DoubleIterator;
+	public static fun iterator-impl ([D)Lkotlin/collections/DoubleIterator;
+	public fun set (ID)V
 	public synthetic fun set (ILjava/lang/Object;)V
-	public static fun set-impl ([III)V
+	public static fun set-impl ([DID)V
 	public fun toString ()Ljava/lang/String;
-	public static fun toString-impl ([I)Ljava/lang/String;
-	public final synthetic fun unbox-impl ()[I
+	public static fun toString-impl ([D)Ljava/lang/String;
+	public final synthetic fun unbox-impl ()[D
 }
 
-public final class space/kscience/kmath/structures/IntBufferKt {
-	public static final fun IntBuffer (ILkotlin/jvm/functions/Function1;)[I
-	public static final fun IntBuffer ([I)[I
-	public static final fun asBuffer ([I)[I
-	public static final fun toIntArray (Lspace/kscience/kmath/structures/Buffer;)[I
+public final class space/kscience/kmath/structures/Float64Buffer$Companion {
+	public final fun zero-qFCK38E (I)[D
 }
 
-public final class space/kscience/kmath/structures/ListBuffer : space/kscience/kmath/structures/Buffer {
-	public fun <init> (ILkotlin/jvm/functions/Function1;)V
-	public fun <init> (Ljava/util/List;)V
-	public fun get (I)Ljava/lang/Object;
-	public final fun getList ()Ljava/util/List;
-	public fun getSize ()I
-	public fun iterator ()Ljava/util/Iterator;
-	public fun toString ()Ljava/lang/String;
+public final class space/kscience/kmath/structures/Float64BufferKt {
+	public static final fun Float64Buffer (ILkotlin/jvm/functions/Function1;)[D
+	public static final fun Float64Buffer ([D)[D
+	public static final fun asBuffer ([D)[D
+	public static final fun toDoubleArray (Lspace/kscience/kmath/structures/Buffer;)[D
+	public static final fun toFloat64Buffer (Lspace/kscience/kmath/structures/Buffer;)[D
 }
 
-public final class space/kscience/kmath/structures/ListBufferKt {
-	public static final fun asBuffer (Ljava/util/List;)Lspace/kscience/kmath/structures/ListBuffer;
-	public static final fun asMutableBuffer (Ljava/util/List;)Ljava/util/List;
+public abstract interface class space/kscience/kmath/structures/Float64BufferTransform : space/kscience/kmath/operations/BufferTransform {
+	public synthetic fun transform (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
+	public abstract fun transform-kPrB3XE ([D)[D
+	public fun transform-qFCK38E (Lspace/kscience/kmath/structures/Buffer;)[D
 }
 
-public final class space/kscience/kmath/structures/LongBuffer : space/kscience/kmath/structures/PrimitiveBuffer {
-	public static final synthetic fun box-impl ([J)Lspace/kscience/kmath/structures/LongBuffer;
-	public static fun constructor-impl ([J)[J
-	public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer;
-	public static fun copy-impl ([J)Lspace/kscience/kmath/structures/MutableBuffer;
-	public fun equals (Ljava/lang/Object;)Z
-	public static fun equals-impl ([JLjava/lang/Object;)Z
-	public static final fun equals-impl0 ([J[J)Z
-	public fun get (I)Ljava/lang/Long;
-	public synthetic fun get (I)Ljava/lang/Object;
-	public static fun get-impl ([JI)Ljava/lang/Long;
-	public final fun getArray ()[J
-	public fun getSize ()I
-	public static fun getSize-impl ([J)I
-	public fun hashCode ()I
-	public static fun hashCode-impl ([J)I
-	public synthetic fun iterator ()Ljava/util/Iterator;
-	public fun iterator ()Lkotlin/collections/LongIterator;
-	public static fun iterator-impl ([J)Lkotlin/collections/LongIterator;
-	public fun set (IJ)V
-	public synthetic fun set (ILjava/lang/Object;)V
-	public static fun set-impl ([JIJ)V
-	public fun toString ()Ljava/lang/String;
-	public static fun toString-impl ([J)Ljava/lang/String;
-	public final synthetic fun unbox-impl ()[J
-}
-
-public final class space/kscience/kmath/structures/LongBufferKt {
-	public static final fun LongBuffer (ILkotlin/jvm/functions/Function1;)[J
-	public static final fun LongBuffer ([J)[J
-	public static final fun asBuffer ([J)[J
-	public static final fun toLongArray (Lspace/kscience/kmath/structures/Buffer;)[J
-}
-
-public class space/kscience/kmath/structures/MemoryBuffer : space/kscience/kmath/structures/Buffer {
-	public static final field Companion Lspace/kscience/kmath/structures/MemoryBuffer$Companion;
-	public fun <init> (Lspace/kscience/kmath/memory/Memory;Lspace/kscience/kmath/memory/MemorySpec;)V
-	public fun get (I)Ljava/lang/Object;
-	protected final fun getMemory ()Lspace/kscience/kmath/memory/Memory;
-	public fun getSize ()I
-	protected final fun getSpec ()Lspace/kscience/kmath/memory/MemorySpec;
-	public fun iterator ()Ljava/util/Iterator;
-	public fun toString ()Ljava/lang/String;
-}
-
-public final class space/kscience/kmath/structures/MemoryBuffer$Companion {
-	public final fun create (Lspace/kscience/kmath/memory/MemorySpec;I)Lspace/kscience/kmath/structures/MemoryBuffer;
-	public final fun create (Lspace/kscience/kmath/memory/MemorySpec;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MemoryBuffer;
-}
-
-public abstract interface class space/kscience/kmath/structures/MutableBuffer : space/kscience/kmath/structures/Buffer {
-	public static final field Companion Lspace/kscience/kmath/structures/MutableBuffer$Companion;
-	public abstract fun copy ()Lspace/kscience/kmath/structures/MutableBuffer;
-	public abstract fun set (ILjava/lang/Object;)V
-}
-
-public final class space/kscience/kmath/structures/MutableBuffer$Companion {
-	public final fun auto (Lkotlin/reflect/KClass;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableBuffer;
-	public final fun boxing (ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableBuffer;
-	public final fun double-CZ9oacQ (ILkotlin/jvm/functions/Function1;)[D
-	public final fun float-YxruXGw (ILkotlin/jvm/functions/Function1;)[F
-	public final fun int-Ye6GY2U (ILkotlin/jvm/functions/Function1;)[I
-	public final fun long-BuQOeTY (ILkotlin/jvm/functions/Function1;)[J
-	public final fun short-1yRgbGw (ILkotlin/jvm/functions/Function1;)[S
-}
-
-public abstract interface class space/kscience/kmath/structures/MutableBufferFactory : space/kscience/kmath/structures/BufferFactory {
-	public static final field Companion Lspace/kscience/kmath/structures/MutableBufferFactory$Companion;
-	public abstract fun invoke (ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableBuffer;
-}
-
-public final class space/kscience/kmath/structures/MutableBufferFactory$Companion {
-	public final fun boxing ()Lspace/kscience/kmath/structures/MutableBufferFactory;
-}
-
-public final class space/kscience/kmath/structures/MutableListBuffer : space/kscience/kmath/structures/MutableBuffer {
-	public static final synthetic fun box-impl (Ljava/util/List;)Lspace/kscience/kmath/structures/MutableListBuffer;
-	public static fun constructor-impl (ILkotlin/jvm/functions/Function1;)Ljava/util/List;
-	public static fun constructor-impl (Ljava/util/List;)Ljava/util/List;
-	public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer;
-	public static fun copy-impl (Ljava/util/List;)Lspace/kscience/kmath/structures/MutableBuffer;
-	public fun equals (Ljava/lang/Object;)Z
-	public static fun equals-impl (Ljava/util/List;Ljava/lang/Object;)Z
-	public static final fun equals-impl0 (Ljava/util/List;Ljava/util/List;)Z
-	public fun get (I)Ljava/lang/Object;
-	public static fun get-impl (Ljava/util/List;I)Ljava/lang/Object;
-	public final fun getList ()Ljava/util/List;
-	public fun getSize ()I
-	public static fun getSize-impl (Ljava/util/List;)I
-	public fun hashCode ()I
-	public static fun hashCode-impl (Ljava/util/List;)I
-	public fun iterator ()Ljava/util/Iterator;
-	public static fun iterator-impl (Ljava/util/List;)Ljava/util/Iterator;
-	public fun set (ILjava/lang/Object;)V
-	public static fun set-impl (Ljava/util/List;ILjava/lang/Object;)V
-	public fun toString ()Ljava/lang/String;
-	public static fun toString-impl (Ljava/util/List;)Ljava/lang/String;
-	public final synthetic fun unbox-impl ()Ljava/util/List;
-}
-
-public final class space/kscience/kmath/structures/MutableMemoryBuffer : space/kscience/kmath/structures/MemoryBuffer, space/kscience/kmath/structures/MutableBuffer {
-	public static final field Companion Lspace/kscience/kmath/structures/MutableMemoryBuffer$Companion;
-	public fun <init> (Lspace/kscience/kmath/memory/Memory;Lspace/kscience/kmath/memory/MemorySpec;)V
-	public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer;
-	public fun set (ILjava/lang/Object;)V
-}
-
-public final class space/kscience/kmath/structures/MutableMemoryBuffer$Companion {
-	public final fun create (Lspace/kscience/kmath/memory/MemorySpec;I)Lspace/kscience/kmath/structures/MutableMemoryBuffer;
-	public final fun create (Lspace/kscience/kmath/memory/MemorySpec;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableMemoryBuffer;
-}
-
-public final class space/kscience/kmath/structures/PermutedBuffer : space/kscience/kmath/structures/BufferView {
-	public fun <init> (Lspace/kscience/kmath/structures/Buffer;[I)V
-	public fun get (I)Ljava/lang/Object;
-	public fun getOrigin ()Lspace/kscience/kmath/structures/Buffer;
-	public fun getSize ()I
-	public fun iterator ()Ljava/util/Iterator;
-	public fun toString ()Ljava/lang/String;
-}
-
-public final class space/kscience/kmath/structures/PermutedMutableBuffer : space/kscience/kmath/structures/BufferView, space/kscience/kmath/structures/MutableBuffer {
-	public fun <init> (Lspace/kscience/kmath/structures/MutableBuffer;[I)V
-	public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer;
-	public fun get (I)Ljava/lang/Object;
-	public synthetic fun getOrigin ()Lspace/kscience/kmath/structures/Buffer;
-	public fun getOrigin ()Lspace/kscience/kmath/structures/MutableBuffer;
-	public fun getSize ()I
-	public fun iterator ()Ljava/util/Iterator;
-	public fun set (ILjava/lang/Object;)V
-	public fun toString ()Ljava/lang/String;
-}
-
-public abstract interface class space/kscience/kmath/structures/PrimitiveBuffer : space/kscience/kmath/structures/MutableBuffer {
-}
-
-public final class space/kscience/kmath/structures/ReadOnlyBuffer : space/kscience/kmath/structures/Buffer {
-	public static final synthetic fun box-impl (Lspace/kscience/kmath/structures/MutableBuffer;)Lspace/kscience/kmath/structures/ReadOnlyBuffer;
-	public static fun constructor-impl (Lspace/kscience/kmath/structures/MutableBuffer;)Lspace/kscience/kmath/structures/MutableBuffer;
-	public fun equals (Ljava/lang/Object;)Z
-	public static fun equals-impl (Lspace/kscience/kmath/structures/MutableBuffer;Ljava/lang/Object;)Z
-	public static final fun equals-impl0 (Lspace/kscience/kmath/structures/MutableBuffer;Lspace/kscience/kmath/structures/MutableBuffer;)Z
-	public fun get (I)Ljava/lang/Object;
-	public static fun get-impl (Lspace/kscience/kmath/structures/MutableBuffer;I)Ljava/lang/Object;
-	public final fun getBuffer ()Lspace/kscience/kmath/structures/MutableBuffer;
-	public fun getSize ()I
-	public static fun getSize-impl (Lspace/kscience/kmath/structures/MutableBuffer;)I
-	public fun hashCode ()I
-	public static fun hashCode-impl (Lspace/kscience/kmath/structures/MutableBuffer;)I
-	public fun iterator ()Ljava/util/Iterator;
-	public static fun iterator-impl (Lspace/kscience/kmath/structures/MutableBuffer;)Ljava/util/Iterator;
-	public fun toString ()Ljava/lang/String;
-	public static fun toString-impl (Lspace/kscience/kmath/structures/MutableBuffer;)Ljava/lang/String;
-	public final synthetic fun unbox-impl ()Lspace/kscience/kmath/structures/MutableBuffer;
-}
-
-public final class space/kscience/kmath/structures/ShortBuffer : space/kscience/kmath/structures/MutableBuffer {
-	public static final synthetic fun box-impl ([S)Lspace/kscience/kmath/structures/ShortBuffer;
+public final class space/kscience/kmath/structures/Int16Buffer : space/kscience/kmath/structures/MutableBuffer {
+	public static final synthetic fun box-impl ([S)Lspace/kscience/kmath/structures/Int16Buffer;
 	public static fun constructor-impl ([S)[S
-	public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer;
-	public static fun copy-impl ([S)Lspace/kscience/kmath/structures/MutableBuffer;
 	public fun equals (Ljava/lang/Object;)Z
 	public static fun equals-impl ([SLjava/lang/Object;)Z
 	public static final fun equals-impl0 ([S[S)Z
@@ -2675,18 +2579,201 @@ public final class space/kscience/kmath/structures/ShortBuffer : space/kscience/
 	public final synthetic fun unbox-impl ()[S
 }
 
-public final class space/kscience/kmath/structures/ShortBufferKt {
-	public static final fun ShortBuffer (ILkotlin/jvm/functions/Function1;)[S
-	public static final fun ShortBuffer ([S)[S
+public final class space/kscience/kmath/structures/Int16BufferKt {
+	public static final fun Int16Buffer (ILkotlin/jvm/functions/Function1;)[S
+	public static final fun Int16Buffer ([S)[S
 	public static final fun asBuffer ([S)[S
 	public static final fun toShortArray (Lspace/kscience/kmath/structures/Buffer;)[S
 }
 
+public final class space/kscience/kmath/structures/Int32Buffer : space/kscience/kmath/structures/PrimitiveBuffer {
+	public static final synthetic fun box-impl ([I)Lspace/kscience/kmath/structures/Int32Buffer;
+	public static fun constructor-impl ([I)[I
+	public fun equals (Ljava/lang/Object;)Z
+	public static fun equals-impl ([ILjava/lang/Object;)Z
+	public static final fun equals-impl0 ([I[I)Z
+	public fun get (I)Ljava/lang/Integer;
+	public synthetic fun get (I)Ljava/lang/Object;
+	public static fun get-impl ([II)Ljava/lang/Integer;
+	public final fun getArray ()[I
+	public fun getSize ()I
+	public static fun getSize-impl ([I)I
+	public fun hashCode ()I
+	public static fun hashCode-impl ([I)I
+	public synthetic fun iterator ()Ljava/util/Iterator;
+	public fun iterator ()Lkotlin/collections/IntIterator;
+	public static fun iterator-impl ([I)Lkotlin/collections/IntIterator;
+	public fun set (II)V
+	public synthetic fun set (ILjava/lang/Object;)V
+	public static fun set-impl ([III)V
+	public fun toString ()Ljava/lang/String;
+	public static fun toString-impl ([I)Ljava/lang/String;
+	public final synthetic fun unbox-impl ()[I
+}
+
+public final class space/kscience/kmath/structures/Int32BufferKt {
+	public static final fun Int32Buffer (ILkotlin/jvm/functions/Function1;)[I
+	public static final fun Int32Buffer ([I)[I
+	public static final fun asBuffer ([I)[I
+	public static final fun toIntArray (Lspace/kscience/kmath/structures/Buffer;)[I
+}
+
+public final class space/kscience/kmath/structures/Int64Buffer : space/kscience/kmath/structures/PrimitiveBuffer {
+	public static final synthetic fun box-impl ([J)Lspace/kscience/kmath/structures/Int64Buffer;
+	public static fun constructor-impl ([J)[J
+	public fun equals (Ljava/lang/Object;)Z
+	public static fun equals-impl ([JLjava/lang/Object;)Z
+	public static final fun equals-impl0 ([J[J)Z
+	public fun get (I)Ljava/lang/Long;
+	public synthetic fun get (I)Ljava/lang/Object;
+	public static fun get-impl ([JI)Ljava/lang/Long;
+	public final fun getArray ()[J
+	public fun getSize ()I
+	public static fun getSize-impl ([J)I
+	public fun hashCode ()I
+	public static fun hashCode-impl ([J)I
+	public synthetic fun iterator ()Ljava/util/Iterator;
+	public fun iterator ()Lkotlin/collections/LongIterator;
+	public static fun iterator-impl ([J)Lkotlin/collections/LongIterator;
+	public fun set (IJ)V
+	public synthetic fun set (ILjava/lang/Object;)V
+	public static fun set-impl ([JIJ)V
+	public fun toString ()Ljava/lang/String;
+	public static fun toString-impl ([J)Ljava/lang/String;
+	public final synthetic fun unbox-impl ()[J
+}
+
+public final class space/kscience/kmath/structures/Int64BufferKt {
+	public static final fun Int64Buffer (ILkotlin/jvm/functions/Function1;)[J
+	public static final fun Int64Buffer ([J)[J
+	public static final fun asBuffer ([J)[J
+	public static final fun toLongArray (Lspace/kscience/kmath/structures/Buffer;)[J
+}
+
+public final class space/kscience/kmath/structures/Int8Buffer : space/kscience/kmath/structures/MutableBuffer {
+	public static final synthetic fun box-impl ([B)Lspace/kscience/kmath/structures/Int8Buffer;
+	public static fun constructor-impl ([B)[B
+	public fun equals (Ljava/lang/Object;)Z
+	public static fun equals-impl ([BLjava/lang/Object;)Z
+	public static final fun equals-impl0 ([B[B)Z
+	public fun get (I)Ljava/lang/Byte;
+	public synthetic fun get (I)Ljava/lang/Object;
+	public static fun get-impl ([BI)Ljava/lang/Byte;
+	public final fun getArray ()[B
+	public fun getSize ()I
+	public static fun getSize-impl ([B)I
+	public fun hashCode ()I
+	public static fun hashCode-impl ([B)I
+	public synthetic fun iterator ()Ljava/util/Iterator;
+	public fun iterator ()Lkotlin/collections/ByteIterator;
+	public static fun iterator-impl ([B)Lkotlin/collections/ByteIterator;
+	public fun set (IB)V
+	public synthetic fun set (ILjava/lang/Object;)V
+	public static fun set-impl ([BIB)V
+	public fun toString ()Ljava/lang/String;
+	public static fun toString-impl ([B)Ljava/lang/String;
+	public final synthetic fun unbox-impl ()[B
+}
+
+public final class space/kscience/kmath/structures/Int8BufferKt {
+	public static final fun Int8Buffer (ILkotlin/jvm/functions/Function1;)[B
+	public static final fun Int8Buffer ([B)[B
+	public static final fun asBuffer ([B)[B
+	public static final fun toByteArray (Lspace/kscience/kmath/structures/Buffer;)[B
+}
+
+public final class space/kscience/kmath/structures/ListBuffer : space/kscience/kmath/structures/Buffer {
+	public fun <init> (Ljava/util/List;)V
+	public fun get (I)Ljava/lang/Object;
+	public final fun getList ()Ljava/util/List;
+	public fun getSize ()I
+	public fun iterator ()Ljava/util/Iterator;
+	public fun toString ()Ljava/lang/String;
+}
+
+public final class space/kscience/kmath/structures/ListBufferKt {
+	public static final fun asBuffer (Ljava/util/List;)Lspace/kscience/kmath/structures/ListBuffer;
+	public static final fun asMutableBuffer (Ljava/util/List;)Lspace/kscience/kmath/structures/MutableListBuffer;
+}
+
+public abstract interface class space/kscience/kmath/structures/MutableBuffer : space/kscience/kmath/structures/Buffer {
+	public static final field Companion Lspace/kscience/kmath/structures/MutableBuffer$Companion;
+	public abstract fun set (ILjava/lang/Object;)V
+}
+
+public final class space/kscience/kmath/structures/MutableBuffer$Companion {
+	public final fun double-Vq5tpWc (ILkotlin/jvm/functions/Function1;)[D
+	public final fun float-pmys_WE (ILkotlin/jvm/functions/Function1;)[F
+	public final fun int-Tednjrs (ILkotlin/jvm/functions/Function1;)[I
+	public final fun long-1n4IcUs (ILkotlin/jvm/functions/Function1;)[J
+	public final fun short-CjmdtSE (ILkotlin/jvm/functions/Function1;)[S
+}
+
+public abstract interface class space/kscience/kmath/structures/MutableBufferFactory : space/kscience/kmath/structures/BufferFactory {
+	public static final field Companion Lspace/kscience/kmath/structures/MutableBufferFactory$Companion;
+	public abstract fun invoke (ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableBuffer;
+}
+
+public final class space/kscience/kmath/structures/MutableBufferFactory$Companion {
+}
+
+public final class space/kscience/kmath/structures/MutableBufferKt {
+	public static final fun MutableBuffer--rwW0uw (Lkotlin/reflect/KType;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableBuffer;
+	public static final fun copy (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/BufferFactory;)Lspace/kscience/kmath/structures/Buffer;
+	public static final fun mutableCopy (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/MutableBufferFactory;)Lspace/kscience/kmath/structures/MutableBuffer;
+}
+
+public final class space/kscience/kmath/structures/MutableListBuffer : space/kscience/kmath/structures/MutableBuffer {
+	public fun <init> (Ljava/util/List;)V
+	public fun get (I)Ljava/lang/Object;
+	public final fun getList ()Ljava/util/List;
+	public fun getSize ()I
+	public fun iterator ()Ljava/util/Iterator;
+	public fun set (ILjava/lang/Object;)V
+	public fun toString ()Ljava/lang/String;
+}
+
+public final class space/kscience/kmath/structures/ParallelBufferFactory : space/kscience/kmath/structures/MutableBufferFactory {
+	public synthetic fun <init> (Lkotlin/reflect/KType;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+	public fun getType-V0oMfBY ()Lkotlin/reflect/KType;
+	public synthetic fun invoke (ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer;
+	public fun invoke (ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableBuffer;
+}
+
+public final class space/kscience/kmath/structures/ParallelMutableBufferKt {
+	public static final fun parallel-Fnn_obI (Lspace/kscience/kmath/structures/MutableBufferFactory$Companion;Lkotlin/reflect/KType;)Lspace/kscience/kmath/structures/MutableBufferFactory;
+	public static final fun parallel-wcOc40k (Lspace/kscience/kmath/structures/MutableBuffer$Companion;Lkotlin/reflect/KType;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableBuffer;
+}
+
+public final class space/kscience/kmath/structures/PermutedBuffer : space/kscience/kmath/structures/BufferView {
+	public fun <init> (Lspace/kscience/kmath/structures/Buffer;[I)V
+	public fun get (I)Ljava/lang/Object;
+	public fun getOrigin ()Lspace/kscience/kmath/structures/Buffer;
+	public fun getSize ()I
+	public fun iterator ()Ljava/util/Iterator;
+	public fun toString ()Ljava/lang/String;
+}
+
+public final class space/kscience/kmath/structures/PermutedMutableBuffer : space/kscience/kmath/structures/BufferView, space/kscience/kmath/structures/MutableBuffer {
+	public fun <init> (Lspace/kscience/kmath/structures/MutableBuffer;[I)V
+	public fun get (I)Ljava/lang/Object;
+	public synthetic fun getOrigin ()Lspace/kscience/kmath/structures/Buffer;
+	public fun getOrigin ()Lspace/kscience/kmath/structures/MutableBuffer;
+	public fun getSize ()I
+	public fun iterator ()Ljava/util/Iterator;
+	public fun set (ILjava/lang/Object;)V
+	public fun toString ()Ljava/lang/String;
+}
+
+public abstract interface class space/kscience/kmath/structures/PrimitiveBuffer : space/kscience/kmath/structures/MutableBuffer {
+}
+
 public final class space/kscience/kmath/structures/ValueFlag : java/lang/Enum {
 	public static final field MISSING Lspace/kscience/kmath/structures/ValueFlag;
 	public static final field NAN Lspace/kscience/kmath/structures/ValueFlag;
 	public static final field NEGATIVE_INFINITY Lspace/kscience/kmath/structures/ValueFlag;
 	public static final field POSITIVE_INFINITY Lspace/kscience/kmath/structures/ValueFlag;
+	public static fun getEntries ()Lkotlin/enums/EnumEntries;
 	public final fun getMask ()B
 	public static fun valueOf (Ljava/lang/String;)Lspace/kscience/kmath/structures/ValueFlag;
 	public static fun values ()[Lspace/kscience/kmath/structures/ValueFlag;
diff --git a/kmath-core/build.gradle.kts b/kmath-core/build.gradle.kts
index 8c622e8b0..699dd82e2 100644
--- a/kmath-core/build.gradle.kts
+++ b/kmath-core/build.gradle.kts
@@ -2,29 +2,14 @@ plugins {
     id("space.kscience.gradle.mpp")
 }
 
-kscience{
+kscience {
     jvm()
     js()
     native()
-    wasm{
-        browser {
-            testTask {
-                useKarma {
-                    webpackConfig.experiments.add("topLevelAwait")
-                    useChromeHeadless()
-                }
-            }
-        }
-    }
-
-    wasmTest{
-        dependencies {
-            implementation(kotlin("test"))
-        }
-    }
+    wasm()
 
     dependencies {
-        api(projects.kmathMemory)
+        api(projects.attributesKt)
     }
 
     testDependencies {
@@ -32,6 +17,15 @@ kscience{
     }
 }
 
+kotlin.sourceSets {
+    filter { it.name.contains("test", true) }
+        .map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings)
+        .forEach {
+            it.optIn("space.kscience.kmath.PerformancePitfall")
+            it.optIn("space.kscience.kmath.UnstableKMathAPI")
+        }
+}
+
 readme {
     description = "Core classes, algebra definitions, basic linear algebra"
     maturity = space.kscience.gradle.Maturity.DEVELOPMENT
@@ -77,4 +71,12 @@ readme {
         id = "autodiff",
         ref = "src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt"
     ) { "Automatic differentiation" }
+
+    feature(
+        id = "Parallel linear algebra"
+    ) {
+        """
+            Parallel implementation for `LinearAlgebra`
+        """.trimIndent()
+    }
 }
diff --git a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/annotations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/annotations.kt
similarity index 97%
rename from kmath-memory/src/commonMain/kotlin/space/kscience/kmath/annotations.kt
rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/annotations.kt
index a95b166cf..13db00968 100644
--- a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/annotations.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/annotations.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2023 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt
index 49e2ee8d0..1dd92980e 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt
index de7e6f79b..6fe232579 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -10,6 +10,7 @@ import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.expressions.Symbol
 import space.kscience.kmath.nd.Structure2D
 import space.kscience.kmath.structures.Buffer
+import space.kscience.kmath.structures.VirtualBuffer
 import kotlin.math.max
 
 /**
@@ -33,7 +34,10 @@ public interface XYColumnarData<out T, out X : T, out Y : T> : ColumnarData<T> {
         else -> null
     }
 
-    public companion object{
+    public companion object {
+        /**
+         * Create data form two buffers (zero-copy)
+         */
         @UnstableKMathAPI
         public fun <T, X : T, Y : T> of(x: Buffer<X>, y: Buffer<Y>): XYColumnarData<T, X, Y> {
             require(x.size == y.size) { "Buffer size mismatch. x buffer size is ${x.size}, y buffer size is ${y.size}" }
@@ -43,6 +47,26 @@ public interface XYColumnarData<out T, out X : T, out Y : T> : ColumnarData<T> {
                 override val y: Buffer<Y> = y
             }
         }
+
+        /**
+         * Create two-column data from a list of row-objects (zero-copy)
+         */
+        @UnstableKMathAPI
+        public inline fun <I, T, reified X : T, reified Y : T> ofList(
+            list: List<I>,
+            noinline xConverter: (I) -> X,
+            noinline yConverter: (I) -> Y,
+        ): XYColumnarData<T, X, Y> = object : XYColumnarData<T, X, Y> {
+            override val size: Int get() = list.size
+
+            override val x: Buffer<X> = VirtualBuffer(list.size) {
+                xConverter(list[it])
+            }
+
+            override val y: Buffer<Y> = VirtualBuffer(list.size) {
+                yConverter(list[it])
+            }
+        }
     }
 }
 
@@ -56,9 +80,10 @@ public fun <T> ColumnarData<T>.asXYData(
     ySymbol: Symbol,
 ): XYColumnarData<T, T, T> = object : XYColumnarData<T, T, T> {
     init {
-        requireNotNull(this@asXYData[xSymbol]){"The column with name $xSymbol is not present in $this"}
-        requireNotNull(this@asXYData[ySymbol]){"The column with name $ySymbol is not present in $this"}
+        requireNotNull(this@asXYData[xSymbol]) { "The column with name $xSymbol is not present in $this" }
+        requireNotNull(this@asXYData[ySymbol]) { "The column with name $ySymbol is not present in $this" }
     }
+
     override val size: Int get() = this@asXYData.size
     override val x: Buffer<T> get() = this@asXYData[xSymbol]!!
     override val y: Buffer<T> get() = this@asXYData[ySymbol]!!
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYErrorColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYErrorColumnarData.kt
index 797a25443..258ddc198 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYErrorColumnarData.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYErrorColumnarData.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -27,7 +27,7 @@ public interface XYErrorColumnarData<T, out X : T, out Y : T> : XYColumnarData<T
 
     public companion object {
         public fun <T, X : T, Y : T> of(
-            x: Buffer<X>, y: Buffer<Y>, yErr: Buffer<Y>
+            x: Buffer<X>, y: Buffer<Y>, yErr: Buffer<Y>,
         ): XYErrorColumnarData<T, X, Y> {
             require(x.size == y.size) { "Buffer size mismatch. x buffer size is ${x.size}, y buffer size is ${y.size}" }
             require(y.size == yErr.size) { "Buffer size mismatch. y buffer size is ${x.size}, yErr buffer size is ${y.size}" }
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt
index 846bbad62..2af3c1c19 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt
index eecdcebad..5bfbeb6ac 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt
index d619883b4..79f446f6d 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -23,7 +23,7 @@ public abstract class Domain1D<T : Comparable<T>>(public val range: ClosedRange<
 @UnstableKMathAPI
 public class DoubleDomain1D(
     @Suppress("CanBeParameter") public val doubleRange: ClosedFloatingPointRange<Double>,
-) : Domain1D<Double>(doubleRange), DoubleDomain {
+) : Domain1D<Double>(doubleRange), Float64Domain {
     override fun getLowerBound(num: Int): Double {
         require(num == 0)
         return range.start
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Float64Domain.kt
similarity index 86%
rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt
rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Float64Domain.kt
index e56173624..a522381e1 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Float64Domain.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 package space.kscience.kmath.domains
@@ -12,7 +12,7 @@ import space.kscience.kmath.UnstableKMathAPI
  * @author Alexander Nozik
  */
 @UnstableKMathAPI
-public interface DoubleDomain : Domain<Double> {
+public interface Float64Domain : Domain<Double> {
     /**
      * Global lower edge
      * @param num axis number
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt
index 1049a251a..16dae5699 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 package space.kscience.kmath.domains
@@ -7,7 +7,7 @@ package space.kscience.kmath.domains
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.linear.Point
 import space.kscience.kmath.structures.Buffer
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import space.kscience.kmath.structures.indices
 
 /**
@@ -15,7 +15,7 @@ import space.kscience.kmath.structures.indices
  * and a [Buffer] of upper boundaries. Upper should be greater or equals than lower.
  */
 @UnstableKMathAPI
-public class HyperSquareDomain(public val lower: Buffer<Double>, public val upper: Buffer<Double>) : DoubleDomain {
+public class HyperSquareDomain(public val lower: Buffer<Double>, public val upper: Buffer<Double>) : Float64Domain {
     init {
         require(lower.size == upper.size) {
             "Domain borders size mismatch. Lower borders size is ${lower.size}, but upper borders size is ${upper.size}."
@@ -27,7 +27,7 @@ public class HyperSquareDomain(public val lower: Buffer<Double>, public val uppe
 
     override val dimension: Int get() = lower.size
 
-    public val center: DoubleBuffer get() = DoubleBuffer(dimension) { (lower[it] + upper[it]) / 2.0 }
+    public val center: Float64Buffer get() = Float64Buffer(dimension) { (lower[it] + upper[it]) / 2.0 }
 
     override operator fun contains(point: Point<Double>): Boolean = point.indices.all { i ->
         point[i] in lower[i]..upper[i]
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt
index 5351a295d..f651dcde3 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 package space.kscience.kmath.domains
@@ -8,7 +8,7 @@ import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.linear.Point
 
 @UnstableKMathAPI
-public class UnconstrainedDomain(override val dimension: Int) : DoubleDomain {
+public class UnconstrainedDomain(override val dimension: Int) : Float64Domain {
     override operator fun contains(point: Point<Double>): Boolean = true
 
     override fun getLowerBound(num: Int): Double = Double.NEGATIVE_INFINITY
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt
index 8c7cb0cf1..a6e721d13 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt
@@ -1,10 +1,11 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.expressions
 
+import space.kscience.attributes.SafeType
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.operations.*
 import space.kscience.kmath.structures.Buffer
@@ -82,6 +83,8 @@ public abstract class DSAlgebra<T, A : Ring<T>>(
     bindings: Map<Symbol, T>,
 ) : ExpressionAlgebra<T, DS<T, A>>, SymbolIndexer {
 
+    override val bufferFactory: MutableBufferFactory<DS<T, A>> = MutableBufferFactory()
+
     /**
      * Get the compiler for number of free parameters and order.
      *
@@ -186,7 +189,7 @@ public abstract class DSAlgebra<T, A : Ring<T>>(
         vararg derivatives: T,
     ): DS<T, A> {
         require(derivatives.size == compiler.size) { "dimension mismatch: ${derivatives.size} and ${compiler.size}" }
-        val data = derivatives.asBuffer()
+        val data = derivatives.asList().asBuffer()
 
         return DS(data)
     }
@@ -329,10 +332,13 @@ public class DerivativeStructureRingExpression<T, A>(
     public val elementBufferFactory: MutableBufferFactory<T> = algebra.bufferFactory,
     public val function: DSRing<T, A>.() -> DS<T, A>,
 ) : DifferentiableExpression<T> where A : Ring<T>, A : ScaleOperations<T>, A : NumericAlgebra<T> {
+
+    override val type: SafeType<T> get() = elementBufferFactory.type
+
     override operator fun invoke(arguments: Map<Symbol, T>): T =
         DSRing(algebra, 0, arguments).function().value
 
-    override fun derivativeOrNull(symbols: List<Symbol>): Expression<T> = Expression { arguments ->
+    override fun derivativeOrNull(symbols: List<Symbol>): Expression<T> = Expression(type) { arguments ->
         with(
             DSRing(
                 algebra,
@@ -441,10 +447,13 @@ public class DSFieldExpression<T, A : ExtendedField<T>>(
     public val algebra: A,
     public val function: DSField<T, A>.() -> DS<T, A>,
 ) : DifferentiableExpression<T> {
+
+    override val type: SafeType<T> get() = algebra.type
+
     override operator fun invoke(arguments: Map<Symbol, T>): T =
         DSField(algebra, 0, arguments).function().value
 
-    override fun derivativeOrNull(symbols: List<Symbol>): Expression<T> = Expression { arguments ->
+    override fun derivativeOrNull(symbols: List<Symbol>): Expression<T> = Expression(type) { arguments ->
         DSField(
             algebra,
             symbols.size,
@@ -464,4 +473,4 @@ public class DSFieldProcessor<T, A : ExtendedField<T>>(
 }
 
 @UnstableKMathAPI
-public val Double.Companion.autodiff: DSFieldProcessor<Double, DoubleField> get() = DSFieldProcessor(DoubleField)
\ No newline at end of file
+public val Double.Companion.autodiff: DSFieldProcessor<Double, Float64Field> get() = DSFieldProcessor(Float64Field)
\ No newline at end of file
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt
index 1da151d46..0699ca1df 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt
index 7c8a957c7..e76374b50 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt
index f350303bc..f2e134963 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt
@@ -1,12 +1,18 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.expressions
 
+import space.kscience.attributes.SafeType
+import space.kscience.attributes.WithType
+import space.kscience.attributes.safeTypeOf
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.operations.Algebra
+import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.IntRing
+import space.kscience.kmath.operations.LongRing
 import kotlin.jvm.JvmName
 import kotlin.properties.ReadOnlyProperty
 
@@ -15,7 +21,7 @@ import kotlin.properties.ReadOnlyProperty
  *
  * @param T the type this expression takes as argument and returns.
  */
-public fun interface Expression<T> {
+public interface Expression<T> : WithType<T> {
     /**
      * Calls this expression from arguments.
      *
@@ -25,11 +31,26 @@ public fun interface Expression<T> {
     public operator fun invoke(arguments: Map<Symbol, T>): T
 }
 
+/**
+ * Create an expression from a functional block.
+ */
+public fun <T> Expression(type: SafeType<T>, block: (Map<Symbol, T>) -> T): Expression<T> = object : Expression<T> {
+    override fun invoke(arguments: Map<Symbol, T>): T = block(arguments)
+
+    override val type: SafeType<T> = type
+}
+
+public inline fun <reified T> Expression(noinline block: (Map<Symbol, T>) -> T): Expression<T> =
+    Expression(safeTypeOf<T>(), block)
+
 /**
  * Specialization of [Expression] for [Double] allowing better performance because of using array.
  */
 @UnstableKMathAPI
 public interface DoubleExpression : Expression<Double> {
+
+    override val type: SafeType<Double> get() = DoubleField.type
+
     /**
      * The indexer of this expression's arguments that should be used to build array for [invoke].
      *
@@ -49,7 +70,7 @@ public interface DoubleExpression : Expression<Double> {
      */
     public operator fun invoke(arguments: DoubleArray): Double
 
-    public companion object{
+    public companion object {
         internal val EMPTY_DOUBLE_ARRAY = DoubleArray(0)
     }
 }
@@ -59,6 +80,9 @@ public interface DoubleExpression : Expression<Double> {
  */
 @UnstableKMathAPI
 public interface IntExpression : Expression<Int> {
+
+    override val type: SafeType<Int> get() = IntRing.type
+
     /**
      * The indexer of this expression's arguments that should be used to build array for [invoke].
      *
@@ -78,7 +102,7 @@ public interface IntExpression : Expression<Int> {
      */
     public operator fun invoke(arguments: IntArray): Int
 
-    public companion object{
+    public companion object {
         internal val EMPTY_INT_ARRAY = IntArray(0)
     }
 }
@@ -88,6 +112,9 @@ public interface IntExpression : Expression<Int> {
  */
 @UnstableKMathAPI
 public interface LongExpression : Expression<Long> {
+
+    override val type: SafeType<Long> get() = LongRing.type
+
     /**
      * The indexer of this expression's arguments that should be used to build array for [invoke].
      *
@@ -107,7 +134,7 @@ public interface LongExpression : Expression<Long> {
      */
     public operator fun invoke(arguments: LongArray): Long
 
-    public companion object{
+    public companion object {
         internal val EMPTY_LONG_ARRAY = LongArray(0)
     }
 }
@@ -158,7 +185,6 @@ public operator fun <T> Expression<T>.invoke(vararg pairs: Pair<String, T>): T =
 )
 
 
-
 /**
  * Calls this expression without providing any arguments.
  *
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/ExpressionWithDefault.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/ExpressionWithDefault.kt
index c802fe04c..5c5fe707e 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/ExpressionWithDefault.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/ExpressionWithDefault.kt
@@ -1,14 +1,19 @@
 /*
- * Copyright 2018-2023 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.expressions
 
+import space.kscience.attributes.SafeType
+
 public class ExpressionWithDefault<T>(
     private val origin: Expression<T>,
     private val defaultArgs: Map<Symbol, T>,
 ) : Expression<T> {
+    override val type: SafeType<T>
+        get() = origin.type
+
     override fun invoke(arguments: Map<Symbol, T>): T = origin.invoke(defaultArgs + arguments)
 }
 
@@ -21,6 +26,9 @@ public class DiffExpressionWithDefault<T>(
     private val defaultArgs: Map<Symbol, T>,
 ) : DifferentiableExpression<T> {
 
+    override val type: SafeType<T>
+        get() = origin.type
+
     override fun invoke(arguments: Map<Symbol, T>): T = origin.invoke(defaultArgs + arguments)
 
     override fun derivativeOrNull(symbols: List<Symbol>): Expression<T>? =
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt
index 1054d1aa1..8ec69c6de 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt
@@ -1,11 +1,12 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.expressions
 
 import space.kscience.kmath.operations.*
+import space.kscience.kmath.structures.MutableBufferFactory
 import kotlin.contracts.InvocationKind
 import kotlin.contracts.contract
 
@@ -17,29 +18,32 @@ import kotlin.contracts.contract
 public abstract class FunctionalExpressionAlgebra<T, out A : Algebra<T>>(
     public val algebra: A,
 ) : ExpressionAlgebra<T, Expression<T>> {
+    override val bufferFactory: MutableBufferFactory<Expression<T>> = MutableBufferFactory<Expression<T>>()
+
     /**
      * 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(algebra.type) { value }
 
     /**
      * Builds an Expression to access a variable.
      */
-    override fun bindSymbolOrNull(value: String): Expression<T>? = Expression { arguments ->
+    override fun bindSymbolOrNull(value: String): Expression<T>? = Expression(algebra.type) { arguments ->
         algebra.bindSymbolOrNull(value)
             ?: arguments[StringSymbol(value)]
             ?: error("Symbol '$value' is not supported in $this")
     }
 
-    override fun binaryOperationFunction(operation: String): (left: Expression<T>, right: Expression<T>) -> Expression<T> =
-        { left, right ->
-            Expression { arguments ->
-                algebra.binaryOperationFunction(operation)(left(arguments), right(arguments))
-            }
+    override fun binaryOperationFunction(
+        operation: String,
+    ): (left: Expression<T>, right: Expression<T>) -> Expression<T> = { left, right ->
+        Expression(algebra.type) { arguments ->
+            algebra.binaryOperationFunction(operation)(left(arguments), right(arguments))
         }
+    }
 
     override fun unaryOperationFunction(operation: String): (arg: Expression<T>) -> Expression<T> = { arg ->
-        Expression { arguments -> algebra.unaryOperation(operation, arg(arguments)) }
+        Expression(algebra.type) { arguments -> algebra.unaryOperation(operation, arg(arguments)) }
     }
 }
 
@@ -49,6 +53,7 @@ public abstract class FunctionalExpressionAlgebra<T, out A : Algebra<T>>(
 public open class FunctionalExpressionGroup<T, out A : Group<T>>(
     algebra: A,
 ) : FunctionalExpressionAlgebra<T, A>(algebra), Group<Expression<T>> {
+
     override val zero: Expression<T> get() = const(algebra.zero)
 
     override fun Expression<T>.unaryMinus(): Expression<T> =
@@ -120,7 +125,7 @@ public open class FunctionalExpressionField<T, out A : Field<T>>(
         super<FunctionalExpressionRing>.binaryOperationFunction(operation)
 
     override fun scale(a: Expression<T>, value: Double): Expression<T> = algebra {
-        Expression { args -> a(args) * value }
+        Expression(algebra.type) { args -> a(args) * value }
     }
 
     override fun bindSymbolOrNull(value: String): Expression<T>? =
@@ -191,6 +196,6 @@ public inline fun <T, A : ExtendedField<T>> A.expressionInExtendedField(
     block: FunctionalExpressionExtendedField<T, A>.() -> Expression<T>,
 ): Expression<T> = FunctionalExpressionExtendedField(this).block()
 
-public inline fun DoubleField.expression(
-    block: FunctionalExpressionExtendedField<Double, DoubleField>.() -> Expression<Double>,
+public inline fun Float64Field.expression(
+    block: FunctionalExpressionExtendedField<Double, Float64Field>.() -> Expression<Double>,
 ): Expression<Double> = FunctionalExpressionExtendedField(this).block()
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt
index 9705a3f03..2d9dcd13d 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -58,6 +58,7 @@ public fun <T> MST.interpret(algebra: Algebra<T>, arguments: Map<Symbol, T>): T
             this.operation,
             algebra.number(this.value.value),
         )
+
         else -> algebra.unaryOperationFunction(this.operation)(this.value.interpret(algebra, arguments))
     }
 
@@ -108,4 +109,4 @@ public fun <T> MST.interpret(algebra: Algebra<T>, vararg arguments: Pair<Symbol,
  * Interpret this [MST] as expression.
  */
 public fun <T : Any> MST.toExpression(algebra: Algebra<T>): Expression<T> =
-    Expression { arguments -> interpret(algebra, arguments) }
+    Expression(algebra.type) { arguments -> interpret(algebra, arguments) }
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt
index c894cf00a..04c2b46da 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,11 +7,14 @@ package space.kscience.kmath.expressions
 
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.operations.*
+import space.kscience.kmath.structures.MutableBufferFactory
 
 /**
  * [Algebra] over [MST] nodes.
  */
 public object MstNumericAlgebra : NumericAlgebra<MST> {
+    override val bufferFactory: MutableBufferFactory<MST> = MutableBufferFactory()
+
     override fun number(value: Number): MST.Numeric = MST.Numeric(value)
     override fun bindSymbolOrNull(value: String): Symbol = StringSymbol(value)
     override fun bindSymbol(value: String): Symbol = bindSymbolOrNull(value)
@@ -27,6 +30,9 @@ public object MstNumericAlgebra : NumericAlgebra<MST> {
  * [Group] over [MST] nodes.
  */
 public object MstGroup : Group<MST>, NumericAlgebra<MST>, ScaleOperations<MST> {
+
+    override val bufferFactory: MutableBufferFactory<MST> = MutableBufferFactory()
+
     override val zero: MST.Numeric = number(0.0)
 
     override fun number(value: Number): MST.Numeric = MstNumericAlgebra.number(value)
@@ -57,7 +63,11 @@ public object MstGroup : Group<MST>, NumericAlgebra<MST>, ScaleOperations<MST> {
 @Suppress("OVERRIDE_BY_INLINE")
 @OptIn(UnstableKMathAPI::class)
 public object MstRing : Ring<MST>, NumbersAddOps<MST>, ScaleOperations<MST> {
+
+    override val bufferFactory: MutableBufferFactory<MST> = MutableBufferFactory()
+
     override inline val zero: MST.Numeric get() = MstGroup.zero
+
     override val one: MST.Numeric = number(1.0)
 
     override fun number(value: Number): MST.Numeric = MstGroup.number(value)
@@ -87,7 +97,11 @@ public object MstRing : Ring<MST>, NumbersAddOps<MST>, ScaleOperations<MST> {
 @Suppress("OVERRIDE_BY_INLINE")
 @OptIn(UnstableKMathAPI::class)
 public object MstField : Field<MST>, NumbersAddOps<MST>, ScaleOperations<MST> {
+
+    override val bufferFactory: MutableBufferFactory<MST> = MutableBufferFactory()
+
     override inline val zero: MST.Numeric get() = MstRing.zero
+
     override inline val one: MST.Numeric get() = MstRing.one
 
     override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value)
@@ -117,7 +131,11 @@ public object MstField : Field<MST>, NumbersAddOps<MST>, ScaleOperations<MST> {
  */
 @Suppress("OVERRIDE_BY_INLINE")
 public object MstExtendedField : ExtendedField<MST>, NumericAlgebra<MST> {
+
+    override val bufferFactory: MutableBufferFactory<MST> = MutableBufferFactory()
+
     override inline val zero: MST.Numeric get() = MstField.zero
+
     override inline val one: MST.Numeric get() = MstField.one
 
     override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value)
@@ -164,6 +182,9 @@ public object MstExtendedField : ExtendedField<MST>, NumericAlgebra<MST> {
  */
 @UnstableKMathAPI
 public object MstLogicAlgebra : LogicAlgebra<MST> {
+
+    override val bufferFactory: MutableBufferFactory<MST> = MutableBufferFactory()
+
     override fun bindSymbolOrNull(value: String): MST = super.bindSymbolOrNull(value) ?: StringSymbol(value)
 
     override fun const(boolean: Boolean): Symbol = if (boolean) {
@@ -176,7 +197,7 @@ public object MstLogicAlgebra : LogicAlgebra<MST> {
 
     override fun MST.and(other: MST): MST = MST.Binary(Boolean::and.name, this, other)
 
-    override fun MST.or(other: MST): MST  = MST.Binary(Boolean::or.name, this, other)
+    override fun MST.or(other: MST): MST = MST.Binary(Boolean::or.name, this, other)
 
-    override fun MST.xor(other: MST): MST  = MST.Binary(Boolean::xor.name, this, other)
+    override fun MST.xor(other: MST): MST = MST.Binary(Boolean::xor.name, this, other)
 }
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt
index 5d047d5b7..14ccafb0b 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2023 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt
index 2bb5043b7..8d7d9e03a 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt
@@ -1,13 +1,16 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.expressions
 
+import space.kscience.attributes.SafeType
+import space.kscience.attributes.WithType
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.linear.Point
 import space.kscience.kmath.operations.*
+import space.kscience.kmath.structures.MutableBufferFactory
 import space.kscience.kmath.structures.asBuffer
 import kotlin.contracts.InvocationKind
 import kotlin.contracts.contract
@@ -30,9 +33,10 @@ public open class AutoDiffValue<out T>(public val value: T)
  */
 public class DerivationResult<T : Any>(
     public val value: T,
+    override val type: SafeType<T>,
     private val derivativeValues: Map<String, T>,
     public val context: Field<T>,
-) {
+) : WithType<T> {
     /**
      * Returns derivative of [variable] or returns [Ring.zero] in [context].
      */
@@ -53,15 +57,19 @@ public fun <T : Any> DerivationResult<T>.grad(vararg variables: Symbol): Point<T
 }
 
 /**
- * Represents field in context of which functions can be derived.
+ * Represents field. Function derivatives could be computed in this field
  */
 @OptIn(UnstableKMathAPI::class)
 public open class SimpleAutoDiffField<T : Any, F : Field<T>>(
-    public val context: F,
+    public val algebra: F,
     bindings: Map<Symbol, T>,
 ) : Field<AutoDiffValue<T>>, ExpressionAlgebra<T, AutoDiffValue<T>>, NumbersAddOps<AutoDiffValue<T>> {
-    override val zero: AutoDiffValue<T> get() = const(context.zero)
-    override val one: AutoDiffValue<T> get() = const(context.one)
+
+    override val bufferFactory: MutableBufferFactory<AutoDiffValue<T>> = MutableBufferFactory<AutoDiffValue<T>>()
+
+    override val zero: AutoDiffValue<T> get() = const(algebra.zero)
+
+    override val one: AutoDiffValue<T> get() = const(algebra.one)
 
     // this stack contains pairs of blocks and values to apply them to
     private var stack: Array<Any?> = arrayOfNulls<Any?>(8)
@@ -69,7 +77,7 @@ public open class SimpleAutoDiffField<T : Any, F : Field<T>>(
     private val derivatives: MutableMap<AutoDiffValue<T>, T> = hashMapOf()
 
     private val bindings: Map<String, AutoDiffVariableWithDerivative<T>> = bindings.entries.associate {
-        it.key.identity to AutoDiffVariableWithDerivative(it.key.identity, it.value, context.zero)
+        it.key.identity to AutoDiffVariableWithDerivative(it.key.identity, it.value, algebra.zero)
     }
 
     /**
@@ -92,7 +100,7 @@ public open class SimpleAutoDiffField<T : Any, F : Field<T>>(
     override fun bindSymbolOrNull(value: String): AutoDiffValue<T>? = bindings[value]
 
     private fun getDerivative(variable: AutoDiffValue<T>): T =
-        (variable as? AutoDiffVariableWithDerivative)?.d ?: derivatives[variable] ?: context.zero
+        (variable as? AutoDiffVariableWithDerivative)?.d ?: derivatives[variable] ?: algebra.zero
 
     private fun setDerivative(variable: AutoDiffValue<T>, value: T) {
         if (variable is AutoDiffVariableWithDerivative) variable.d = value else derivatives[variable] = value
@@ -103,7 +111,7 @@ public open class SimpleAutoDiffField<T : Any, F : Field<T>>(
         while (sp > 0) {
             val value = stack[--sp]
             val block = stack[--sp] as F.(Any?) -> Unit
-            context.block(value)
+            algebra.block(value)
         }
     }
 
@@ -130,7 +138,6 @@ public open class SimpleAutoDiffField<T : Any, F : Field<T>>(
      * }
      * ```
      */
-    @Suppress("UNCHECKED_CAST")
     public fun <R> derive(value: R, block: F.(R) -> Unit): R {
         // save block to stack for backward pass
         if (sp >= stack.size) stack = stack.copyOf(stack.size * 2)
@@ -142,9 +149,9 @@ public open class SimpleAutoDiffField<T : Any, F : Field<T>>(
 
     internal fun differentiate(function: SimpleAutoDiffField<T, F>.() -> AutoDiffValue<T>): DerivationResult<T> {
         val result = function()
-        result.d = context.one // computing derivative w.r.t result
+        result.d = algebra.one // computing derivative w.r.t result
         runBackwardPass()
-        return DerivationResult(result.value, bindings.mapValues { it.value.d }, context)
+        return DerivationResult(result.value, algebra.type, bindings.mapValues { it.value.d }, algebra)
     }
 
 //    // Overloads for Double constants
@@ -194,7 +201,7 @@ public open class SimpleAutoDiffField<T : Any, F : Field<T>>(
 
 public inline fun <T : Any, F : Field<T>> SimpleAutoDiffField<T, F>.const(block: F.() -> T): AutoDiffValue<T> {
     contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
-    return const(context.block())
+    return const(algebra.block())
 }
 
 
@@ -217,11 +224,7 @@ public inline fun <T : Any, F : Field<T>> SimpleAutoDiffField<T, F>.const(block:
 public fun <T : Any, F : Field<T>> F.simpleAutoDiff(
     bindings: Map<Symbol, T>,
     body: SimpleAutoDiffField<T, F>.() -> AutoDiffValue<T>,
-): DerivationResult<T> {
-    contract { callsInPlace(body, InvocationKind.EXACTLY_ONCE) }
-
-    return SimpleAutoDiffField(this, bindings).differentiate(body)
-}
+): DerivationResult<T> = SimpleAutoDiffField(this, bindings).differentiate(body)
 
 public fun <T : Any, F : Field<T>> F.simpleAutoDiff(
     vararg bindings: Pair<Symbol, T>,
@@ -236,12 +239,15 @@ public class SimpleAutoDiffExpression<T : Any, F : Field<T>>(
     public val field: F,
     public val function: SimpleAutoDiffField<T, F>.() -> AutoDiffValue<T>,
 ) : FirstDerivativeExpression<T>() {
+
+    override val type: SafeType<T> get() = this.field.type
+
     override operator fun invoke(arguments: Map<Symbol, T>): T {
         //val bindings = arguments.entries.map { it.key.bind(it.value) }
         return SimpleAutoDiffField(field, arguments).function().value
     }
 
-    override fun derivativeOrNull(symbol: Symbol): Expression<T> = Expression { arguments ->
+    override fun derivativeOrNull(symbol: Symbol): Expression<T> = Expression(type) { arguments ->
         //val bindings = arguments.entries.map { it.key.bind(it.value) }
         val derivationResult = SimpleAutoDiffField(field, arguments).differentiate(function)
         derivationResult.derivative(symbol)
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt
index c57ce69ab..5e2ab64a6 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt
index 7112e921a..d47202df3 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -9,7 +9,7 @@ import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.linear.Point
 import space.kscience.kmath.nd.Structure2D
 import space.kscience.kmath.structures.BufferFactory
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import kotlin.contracts.InvocationKind
 import kotlin.contracts.contract
 import kotlin.jvm.JvmInline
@@ -62,8 +62,8 @@ public interface SymbolIndexer {
     public fun <T> Map<Symbol, T>.toPoint(bufferFactory: BufferFactory<T>): Point<T> =
         bufferFactory(symbols.size) { getValue(symbols[it]) }
 
-    public fun Map<Symbol, Double>.toPoint(): DoubleBuffer =
-        DoubleBuffer(symbols.size) { getValue(symbols[it]) }
+    public fun Map<Symbol, Double>.toPoint(): Float64Buffer =
+        Float64Buffer(symbols.size) { getValue(symbols[it]) }
 
 
     public fun Map<Symbol, Double>.toDoubleArray(): DoubleArray = DoubleArray(symbols.size) { getValue(symbols[it]) }
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt
index 4bba47a91..fca29a9dd 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/DoubleLinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/Float64LinearSpace.kt
similarity index 60%
rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/DoubleLinearSpace.kt
rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/Float64LinearSpace.kt
index 940af4a86..bafdbbc3b 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/DoubleLinearSpace.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/Float64LinearSpace.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,43 +7,43 @@ package space.kscience.kmath.linear
 
 import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.nd.*
-import space.kscience.kmath.operations.DoubleBufferOps
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64BufferOps
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.invoke
 import space.kscience.kmath.structures.Buffer
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 
-public object DoubleLinearSpace : LinearSpace<Double, DoubleField> {
+public object Float64LinearSpace : LinearSpace<Double, Float64Field> {
 
-    override val elementAlgebra: DoubleField get() = DoubleField
+    override val elementAlgebra: Float64Field get() = Float64Field
 
     override fun buildMatrix(
         rows: Int,
         columns: Int,
-        initializer: DoubleField.(i: Int, j: Int) -> Double
-    ): Matrix<Double> = DoubleFieldOpsND.structureND(ShapeND(rows, columns)) { (i, j) ->
-        DoubleField.initializer(i, j)
+        initializer: Float64Field.(i: Int, j: Int) -> Double,
+    ): Matrix<Double> = Floa64FieldOpsND.structureND(ShapeND(rows, columns)) { (i, j) ->
+        Float64Field.initializer(i, j)
     }.as2D()
 
-    override fun buildVector(size: Int, initializer: DoubleField.(Int) -> Double): DoubleBuffer =
-        DoubleBuffer(size) { DoubleField.initializer(it) }
+    override fun buildVector(size: Int, initializer: Float64Field.(Int) -> Double): Float64Buffer =
+        Float64Buffer(size) { Float64Field.initializer(it) }
 
-    override fun Matrix<Double>.unaryMinus(): Matrix<Double> = DoubleFieldOpsND {
+    override fun Matrix<Double>.unaryMinus(): Matrix<Double> = Floa64FieldOpsND {
         asND().map { -it }.as2D()
     }
 
-    override fun Matrix<Double>.plus(other: Matrix<Double>): Matrix<Double> = DoubleFieldOpsND {
+    override fun Matrix<Double>.plus(other: Matrix<Double>): Matrix<Double> = Floa64FieldOpsND {
         require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::plus. Expected $shape but found ${other.shape}" }
         asND().plus(other.asND()).as2D()
     }
 
-    override fun Matrix<Double>.minus(other: Matrix<Double>): Matrix<Double> = DoubleFieldOpsND {
+    override fun Matrix<Double>.minus(other: Matrix<Double>): Matrix<Double> = Floa64FieldOpsND {
         require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::minus. Expected $shape but found ${other.shape}" }
         asND().minus(other.asND()).as2D()
     }
 
     // Create a continuous in-memory representation of this vector for better memory layout handling
-    private fun Buffer<Double>.linearize() = if (this is DoubleBuffer) {
+    private fun Buffer<Double>.linearize() = if (this is Float64Buffer) {
         this.array
     } else {
         DoubleArray(size) { get(it) }
@@ -54,11 +54,12 @@ public object DoubleLinearSpace : LinearSpace<Double, DoubleField> {
         require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" }
         val rows = this@dot.rows.map { it.linearize() }
         val columns = other.columns.map { it.linearize() }
+        val indices = 0 until this.colNum
         return buildMatrix(rowNum, other.colNum) { i, j ->
             val r = rows[i]
             val c = columns[j]
             var res = 0.0
-            for (l in r.indices) {
+            for (l in indices) {
                 res += r[l] * c[l]
             }
             res
@@ -66,13 +67,14 @@ public object DoubleLinearSpace : LinearSpace<Double, DoubleField> {
     }
 
     @OptIn(PerformancePitfall::class)
-    override fun Matrix<Double>.dot(vector: Point<Double>): DoubleBuffer {
+    override fun Matrix<Double>.dot(vector: Point<Double>): Float64Buffer {
         require(colNum == vector.size) { "Matrix dot vector operation dimension mismatch: ($rowNum, $colNum) x (${vector.size})" }
         val rows = this@dot.rows.map { it.linearize() }
-        return DoubleBuffer(rowNum) { i ->
+        val indices = 0 until this.colNum
+        return Float64Buffer(rowNum) { i ->
             val r = rows[i]
             var res = 0.0
-            for (j in r.indices) {
+            for (j in indices) {
                 res += r[j] * vector[j]
             }
             res
@@ -80,29 +82,29 @@ public object DoubleLinearSpace : LinearSpace<Double, DoubleField> {
 
     }
 
-    override fun Matrix<Double>.times(value: Double): Matrix<Double> = DoubleFieldOpsND {
+    override fun Matrix<Double>.times(value: Double): Matrix<Double> = Floa64FieldOpsND {
         asND().map { it * value }.as2D()
     }
 
-    public override fun Point<Double>.plus(other: Point<Double>): DoubleBuffer = DoubleBufferOps.run {
+    public override fun Point<Double>.plus(other: Point<Double>): Float64Buffer = Float64BufferOps.run {
         this@plus + other
     }
 
-    public override fun Point<Double>.minus(other: Point<Double>): DoubleBuffer = DoubleBufferOps.run {
+    public override fun Point<Double>.minus(other: Point<Double>): Float64Buffer = Float64BufferOps.run {
         this@minus - other
     }
 
-    public override fun Point<Double>.times(value: Double): DoubleBuffer = DoubleBufferOps.run {
+    public override fun Point<Double>.times(value: Double): Float64Buffer = Float64BufferOps.run {
         scale(this@times, value)
     }
 
-    public operator fun Point<Double>.div(value: Double): DoubleBuffer = DoubleBufferOps.run {
+    public operator fun Point<Double>.div(value: Double): Float64Buffer = Float64BufferOps.run {
         scale(this@div, 1.0 / value)
     }
 
-    public override fun Double.times(v: Point<Double>): DoubleBuffer = v * this
+    public override fun Double.times(v: Point<Double>): Float64Buffer = v * this
 
 
 }
 
-public val DoubleField.linearSpace: DoubleLinearSpace get() = DoubleLinearSpace
+public val Float64Field.linearSpace: Float64LinearSpace get() = Float64LinearSpace
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt
index af9ebb463..4082b6f4f 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -11,7 +11,7 @@ package space.kscience.kmath.linear
  *
  * @param T the type of items.
  */
-public interface LinearSolver<T : Any> {
+public interface LinearSolver<T> {
     /**
      * Solve a dot x = b matrix equation and return x
      */
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt
index a82bafe57..343470e2e 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt
@@ -1,20 +1,17 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.linear
 
+import space.kscience.attributes.*
 import space.kscience.kmath.UnstableKMathAPI
-import space.kscience.kmath.nd.MutableStructure2D
-import space.kscience.kmath.nd.Structure2D
-import space.kscience.kmath.nd.StructureFeature
-import space.kscience.kmath.nd.as1D
+import space.kscience.kmath.nd.*
 import space.kscience.kmath.operations.BufferRingOps
 import space.kscience.kmath.operations.Ring
 import space.kscience.kmath.operations.invoke
 import space.kscience.kmath.structures.Buffer
-import kotlin.reflect.KClass
 
 /**
  * Alias for [Structure2D] with more familiar name.
@@ -37,9 +34,11 @@ public typealias Point<T> = Buffer<T>
  * @param T the type of items in the matrices.
  * @param A the type of ring over [T].
  */
-public interface LinearSpace<T, out A : Ring<T>> {
+public interface LinearSpace<T, out A : Ring<T>> : MatrixScope<T> {
     public val elementAlgebra: A
 
+    override val type: SafeType<T> get() = elementAlgebra.type
+
     /**
      * Produces a matrix with this context and given dimensions.
      */
@@ -167,16 +166,36 @@ public interface LinearSpace<T, out A : Ring<T>> {
     public operator fun T.times(v: Point<T>): Point<T> = v * this
 
     /**
-     * Compute a feature of the structure in this scope. Structure features take precedence other context features.
+     * Compute an [attribute] value for given [structure]. Return null if the attribute could not be computed.
+     */
+    public fun <V, A : StructureAttribute<V>> computeAttribute(structure: Structure2D<T>, attribute: A): V? = null
+
+    @UnstableKMathAPI
+    public fun <V, A : StructureAttribute<V>> Structure2D<T>.getOrComputeAttribute(attribute: A): V? {
+        return attributes[attribute] ?: computeAttribute(this, attribute)
+    }
+
+    /**
+     * If the structure holds given [attribute] return itself. Otherwise, return a new [Matrix] that contains a computed attribute.
      *
-     * @param F the type of feature.
-     * @param structure the structure.
-     * @param type the [KClass] instance of [F].
-     * @return a feature object or `null` if it isn't present.
+     * This method is used to compute and cache attribute inside the structure. If one needs an attribute only once,
+     * better use [StructureND.getOrComputeAttribute].
      */
     @UnstableKMathAPI
-    public fun <F : StructureFeature> computeFeature(structure: Matrix<T>, type: KClass<out F>): F? =
-        structure.getFeature(type)
+    public fun <V : Any, A : StructureAttribute<V>> Matrix<T>.withComputedAttribute(
+        attribute: A,
+    ): Matrix<T>? {
+        return if (attributes[attribute] != null) {
+            this
+        } else {
+            val value = computeAttribute(this, attribute) ?: return null
+            if (this is MatrixWrapper) {
+                MatrixWrapper(this, attributes.withAttribute(attribute, value))
+            } else {
+                MatrixWrapper(this, Attributes(attribute, value))
+            }
+        }
+    }
 
     public companion object {
 
@@ -184,23 +203,12 @@ public interface LinearSpace<T, out A : Ring<T>> {
          * A structured matrix with custom buffer
          */
         public fun <T : Any, A : Ring<T>> buffered(
-            algebra: A
+            algebra: A,
         ): LinearSpace<T, A> = BufferedLinearSpace(BufferRingOps(algebra))
 
     }
 }
 
-/**
- * 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 F the type of feature.
- * @return a feature object or `null` if it isn't present.
- */
-@UnstableKMathAPI
-public inline fun <T : Any, reified F : StructureFeature> LinearSpace<T, *>.computeFeature(structure: Matrix<T>): F? =
-    computeFeature(structure, F::class)
-
 
 public inline operator fun <LS : LinearSpace<*, *>, R> LS.invoke(block: LS.() -> R): R = run(block)
 
@@ -208,7 +216,7 @@ public inline operator fun <LS : LinearSpace<*, *>, R> LS.invoke(block: LS.() ->
 /**
  * Convert matrix to vector if it is possible.
  */
-public fun <T : Any> Matrix<T>.asVector(): Point<T> =
+public fun <T> Matrix<T>.asVector(): Point<T> =
     if (this.colNum == 1) as1D()
     else error("Can't convert matrix with more than one column to vector")
 
@@ -219,4 +227,4 @@ public fun <T : Any> Matrix<T>.asVector(): Point<T> =
  * @receiver a buffer.
  * @return the new matrix.
  */
-public fun <T : Any> Point<T>.asMatrix(): VirtualMatrix<T> = VirtualMatrix(size, 1) { i, _ -> get(i) }
\ No newline at end of file
+public fun <T> Point<T>.asMatrix(): VirtualMatrix<T> = VirtualMatrix(size, 1) { i, _ -> get(i) }
\ No newline at end of file
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt
index 650e7be5c..03859ba83 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt
@@ -1,70 +1,78 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
+@file:Suppress("UnusedReceiverParameter")
+@file:OptIn(PerformancePitfall::class)
+
 package space.kscience.kmath.linear
 
+import space.kscience.attributes.Attributes
+import space.kscience.attributes.PolymorphicAttribute
+import space.kscience.attributes.safeTypeOf
+import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.UnstableKMathAPI
+import space.kscience.kmath.nd.*
 import space.kscience.kmath.operations.*
-import space.kscience.kmath.structures.BufferAccessor2D
-import space.kscience.kmath.structures.DoubleBuffer
-import space.kscience.kmath.structures.MutableBuffer
-import space.kscience.kmath.structures.MutableBufferFactory
+import space.kscience.kmath.structures.*
+
+public interface LupDecomposition<T> {
+    public val pivot: IntBuffer
+    public val l: Matrix<T>
+    public val u: Matrix<T>
+}
 
 /**
- * Common implementation of [LupDecompositionFeature].
+ * Create a pivot matrix from pivot vector using provided [LinearSpace]
  */
-public class LupDecomposition<T : Any>(
-    public val context: LinearSpace<T, *>,
-    public val elementContext: Field<T>,
-    public val lu: Matrix<T>,
-    public val pivot: IntArray,
-    private val even: Boolean,
-) : LupDecompositionFeature<T>, DeterminantFeature<T> {
-    /**
-     * Returns the matrix L of the decomposition.
-     *
-     * L is a lower-triangular matrix with [Ring.one] in diagonal
-     */
-    override val l: Matrix<T> = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j ->
-        when {
-            j < i -> lu[i, j]
-            j == i -> elementContext.one
-            else -> elementContext.zero
-        }
-    }.withFeature(LFeature)
-
-
-    /**
-     * Returns the matrix U of the decomposition.
-     *
-     * U is an upper-triangular matrix including the diagonal
-     */
-    override val u: Matrix<T> = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j ->
-        if (j >= i) lu[i, j] else elementContext.zero
-    }.withFeature(UFeature)
-
-    /**
-     * Returns the P rows permutation matrix.
-     *
-     * P is a sparse matrix with exactly one element set to [Ring.one] in
-     * each row and each column, all other elements being set to [Ring.zero].
-     */
-    override val p: Matrix<T> = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j ->
-        if (j == pivot[i]) elementContext.one else elementContext.zero
+public fun <T> LupDecomposition<T>.pivotMatrix(linearSpace: LinearSpace<T, Ring<T>>): Matrix<T> =
+    VirtualMatrix(l.rowNum, l.colNum) { row, column ->
+        if (column == pivot[row]) linearSpace.elementAlgebra.one else linearSpace.elementAlgebra.zero
     }
 
-    /**
-     * Return the determinant of the matrix
-     * @return determinant of the matrix
-     */
-    override val determinant: T by lazy {
-        elementContext { (0 until lu.shape[0]).fold(if (even) one else -one) { value, i -> value * lu[i, i] } }
+/**
+ * Matrices with this feature support LU factorization with partial pivoting: *[p] &middot; a = [l] &middot; [u]* where
+ * *a* is the owning matrix.
+ *
+ * @param T the type of matrices' items.
+ * @param lu combined L and U matrix
+ */
+public class GenericLupDecomposition<T>(
+    public val elementAlgebra: Field<T>,
+    private val lu: Matrix<T>,
+    override val pivot: IntBuffer,
+    private val even: Boolean,
+) : LupDecomposition<T> {
+
+
+    override val l: Matrix<T>
+        get() = VirtualMatrix(lu.rowNum, lu.colNum, attributes = Attributes(LowerTriangular)) { i, j ->
+            when {
+                j < i -> lu[i, j]
+                j == i -> elementAlgebra.one
+                else -> elementAlgebra.zero
+            }
+        }
+
+    override val u: Matrix<T>
+        get() = VirtualMatrix(lu.rowNum, lu.colNum, attributes = Attributes(UpperTriangular)) { i, j ->
+            if (j >= i) lu[i, j] else elementAlgebra.zero
+        }
+
+    public val determinant: T by lazy {
+        elementAlgebra { (0 until l.shape[0]).fold(if (even) one else -one) { value, i -> value * lu[i, i] } }
     }
 
 }
 
+public class LupDecompositionAttribute<T> :
+    PolymorphicAttribute<LupDecomposition<T>>(safeTypeOf()),
+    MatrixAttribute<LupDecomposition<T>>
+
+public val <T> MatrixScope<T>.LUP: LupDecompositionAttribute<T>
+    get() = LupDecompositionAttribute()
+
 @PublishedApi
 internal fun <T : Comparable<T>> LinearSpace<T, Ring<T>>.abs(value: T): T =
     if (value > elementAlgebra.zero) value else elementAlgebra { -value }
@@ -72,159 +80,160 @@ internal fun <T : Comparable<T>> LinearSpace<T, Ring<T>>.abs(value: T): T =
 /**
  * Create a lup decomposition of generic matrix.
  */
-public fun <T : Comparable<T>> LinearSpace<T, Field<T>>.lup(
-    factory: MutableBufferFactory<T>,
+public fun <T : Comparable<T>> Field<T>.lup(
     matrix: Matrix<T>,
     checkSingular: (T) -> Boolean,
-): LupDecomposition<T> {
+): GenericLupDecomposition<T> {
     require(matrix.rowNum == matrix.colNum) { "LU decomposition supports only square matrices" }
     val m = matrix.colNum
     val pivot = IntArray(matrix.rowNum)
 
-    //TODO just waits for multi-receivers
-    BufferAccessor2D(matrix.rowNum, matrix.colNum, factory).run {
-        elementAlgebra {
-            val lu = create(matrix)
+    val strides = RowStrides(ShapeND(matrix.rowNum, matrix.colNum))
 
-            // Initialize permutation array and parity
-            for (row in 0 until m) pivot[row] = row
-            var even = true
+    val lu = MutableBufferND(
+        strides,
+        bufferAlgebra.buffer(strides.linearSize) { offset ->
+            matrix[strides.index(offset)]
+        }
+    )
 
-            // Initialize permutation array and parity
-            for (row in 0 until m) pivot[row] = row
 
-            // Loop over columns
-            for (col in 0 until m) {
-                // upper
-                for (row in 0 until col) {
-                    val luRow = lu.row(row)
-                    var sum = luRow[col]
-                    for (i in 0 until row) sum -= luRow[i] * lu[i, col]
-                    luRow[col] = sum
-                }
+    // Initialize the permutation array and parity
+    for (row in 0 until m) pivot[row] = row
+    var even = true
 
-                // lower
-                var max = col // permutation row
-                var largest = -one
+    // Initialize the permutation array and parity
+    for (row in 0 until m) pivot[row] = row
 
-                for (row in col until m) {
-                    val luRow = lu.row(row)
-                    var sum = luRow[col]
-                    for (i in 0 until col) sum -= luRow[i] * lu[i, col]
-                    luRow[col] = sum
+    // Loop over columns
+    for (col in 0 until m) {
+        // upper
+        for (row in 0 until col) {
+            var sum = lu[row, col]
+            for (i in 0 until row) {
+                sum -= lu[row, i] * lu[i, col]
+            }
+            lu[row, col] = sum
+        }
 
-                    // maintain the best permutation choice
-                    if (abs(sum) > largest) {
-                        largest = abs(sum)
-                        max = row
-                    }
-                }
+        // lower
+        var max = col // permutation row
+        var largest = -one
 
-                // Singularity check
-                check(!checkSingular(abs(lu[max, col]))) { "The matrix is singular" }
+        for (row in col until m) {
+            var sum = lu[row, col]
+            for (i in 0 until col) {
+                sum -= lu[row, i] * lu[i, col]
+            }
+            lu[row, col] = sum
 
-                // Pivot if necessary
-                if (max != col) {
-                    val luMax = lu.row(max)
-                    val luCol = lu.row(col)
+            // maintain the best permutation choice
+            if (abs(sum) > largest) {
+                largest = abs(sum)
+                max = row
+            }
+        }
 
-                    for (i in 0 until m) {
-                        val tmp = luMax[i]
-                        luMax[i] = luCol[i]
-                        luCol[i] = tmp
-                    }
+        // Singularity check
+        check(!checkSingular(abs(lu[max, col]))) { "The matrix is singular" }
 
-                    val temp = pivot[max]
-                    pivot[max] = pivot[col]
-                    pivot[col] = temp
-                    even = !even
-                }
-
-                // Divide the lower elements by the "winning" diagonal elt.
-                val luDiag = lu[col, col]
-                for (row in col + 1 until m) lu[row, col] /= luDiag
+        // Pivot if necessary
+        if (max != col) {
+            for (i in 0 until m) {
+                val tmp = lu[max, i]
+                lu[max, i] = lu[col, i]
+                lu[col, i] = tmp
             }
 
-            return LupDecomposition(this@lup, elementAlgebra, lu.collect(), pivot, even)
+            val temp = pivot[max]
+            pivot[max] = pivot[col]
+            pivot[col] = temp
+            even = !even
         }
+
+        // Divide the lower elements by the "winning" diagonal elt.
+        val luDiag = lu[col, col]
+        for (row in col + 1 until m) lu[row, col] /= luDiag
     }
+
+
+    return GenericLupDecomposition(this, lu.as2D(), pivot.asBuffer(), even)
+
 }
 
-public inline fun <reified T : Comparable<T>> LinearSpace<T, Field<T>>.lup(
-    matrix: Matrix<T>,
-    noinline checkSingular: (T) -> Boolean,
-): LupDecomposition<T> = lup(MutableBuffer.Companion::auto, matrix, checkSingular)
 
-public fun LinearSpace<Double, DoubleField>.lup(
+public fun Field<Float64>.lup(
     matrix: Matrix<Double>,
     singularityThreshold: Double = 1e-11,
-): LupDecomposition<Double> =
-    lup(::DoubleBuffer, matrix) { it < singularityThreshold }
+): GenericLupDecomposition<Double> = lup(matrix) { it < singularityThreshold }
 
-internal fun <T : Any> LupDecomposition<T>.solve(
-    factory: MutableBufferFactory<T>,
+private fun <T> Field<T>.solve(
+    lup: LupDecomposition<T>,
     matrix: Matrix<T>,
 ): Matrix<T> {
-    require(matrix.rowNum == pivot.size) { "Matrix dimension mismatch. Expected ${pivot.size}, but got ${matrix.colNum}" }
+    require(matrix.rowNum == lup.l.rowNum) { "Matrix dimension mismatch. Expected ${lup.l.rowNum}, but got ${matrix.colNum}" }
 
-    BufferAccessor2D(matrix.rowNum, matrix.colNum, factory).run {
-        elementContext {
-            // Apply permutations to b
-            val bp = create { _, _ -> zero }
+    val strides = RowStrides(ShapeND(matrix.rowNum, matrix.colNum))
 
-            for (row in pivot.indices) {
-                val bpRow = bp.row(row)
-                val pRow = pivot[row]
-                for (col in 0 until matrix.colNum) bpRow[col] = matrix[pRow, col]
-            }
+    // Apply permutations to b
+    val bp = MutableBufferND(
+        strides,
+        bufferAlgebra.buffer(strides.linearSize) { _ -> zero }
+    )
 
-            // Solve LY = b
-            for (col in pivot.indices) {
-                val bpCol = bp.row(col)
 
-                for (i in col + 1 until pivot.size) {
-                    val bpI = bp.row(i)
-                    val luICol = lu[i, col]
-                    for (j in 0 until matrix.colNum) {
-                        bpI[j] -= bpCol[j] * luICol
-                    }
-                }
-            }
-
-            // Solve UX = Y
-            for (col in pivot.size - 1 downTo 0) {
-                val bpCol = bp.row(col)
-                val luDiag = lu[col, col]
-                for (j in 0 until matrix.colNum) bpCol[j] /= luDiag
-
-                for (i in 0 until col) {
-                    val bpI = bp.row(i)
-                    val luICol = lu[i, col]
-                    for (j in 0 until matrix.colNum) bpI[j] -= bpCol[j] * luICol
-                }
-            }
-
-            return context.buildMatrix(pivot.size, matrix.colNum) { i, j -> bp[i, j] }
+    for (row in 0 until matrix.rowNum) {
+        val pRow = lup.pivot[row]
+        for (col in 0 until matrix.colNum) {
+            bp[row, col] = matrix[pRow, col]
         }
     }
+
+    // Solve LY = b
+    for (col in 0 until matrix.colNum) {
+
+        for (i in col + 1 until matrix.colNum) {
+            val luICol = lup.l[i, col]
+            for (j in 0 until matrix.colNum) {
+                bp[i, j] -= bp[col, j] * luICol
+            }
+        }
+    }
+
+    // Solve UX = Y
+    for (col in matrix.colNum - 1 downTo 0) {
+        val luDiag = lup.u[col, col]
+        for (j in 0 until matrix.colNum) {
+            bp[col, j] /= luDiag
+        }
+
+        for (i in 0 until col) {
+            val luICol = lup.u[i, col]
+            for (j in 0 until matrix.colNum) {
+                bp[i, j] -= bp[col, j] * luICol
+            }
+        }
+    }
+
+    return bp.as2D()
 }
 
+
 /**
  * Produce a generic solver based on LUP decomposition
  */
 @OptIn(UnstableKMathAPI::class)
-public fun <T : Comparable<T>, F : Field<T>> LinearSpace<T, F>.lupSolver(
-    bufferFactory: MutableBufferFactory<T>,
+public fun <T : Comparable<T>> LinearSpace<T, Field<T>>.lupSolver(
     singularityCheck: (T) -> Boolean,
 ): LinearSolver<T> = object : LinearSolver<T> {
-    override fun solve(a: Matrix<T>, b: Matrix<T>): Matrix<T> {
-        // Use existing decomposition if it is provided by matrix
-        val decomposition = computeFeature(a) ?: lup(bufferFactory, a, singularityCheck)
-        return decomposition.solve(bufferFactory, b)
+    override fun solve(a: Matrix<T>, b: Matrix<T>): Matrix<T> = elementAlgebra {
+        // Use existing decomposition if it is provided by matrix or linear space itself
+        val decomposition = a.getOrComputeAttribute(LUP) ?: lup(a, singularityCheck)
+        return solve(decomposition, b)
     }
 
     override fun inverse(matrix: Matrix<T>): Matrix<T> = solve(matrix, one(matrix.rowNum, matrix.colNum))
 }
 
-public fun LinearSpace<Double, DoubleField>.lupSolver(singularityThreshold: Double = 1e-11): LinearSolver<Double> =
-    lupSolver(::DoubleBuffer) { it < singularityThreshold }
+public fun LinearSpace<Double, Float64Field>.lupSolver(singularityThreshold: Double = 1e-11): LinearSolver<Double> =
+    lupSolver { it < singularityThreshold }
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt
index 4d2f01e68..18e1edb56 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt
@@ -1,20 +1,26 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.linear
 
+import space.kscience.attributes.FlagAttribute
+import space.kscience.attributes.SafeType
+import space.kscience.attributes.WithType
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.operations.Ring
 import space.kscience.kmath.structures.BufferAccessor2D
-import space.kscience.kmath.structures.MutableBuffer
+import space.kscience.kmath.structures.MutableBufferFactory
 
 public class MatrixBuilder<T : Any, out A : Ring<T>>(
     public val linearSpace: LinearSpace<T, A>,
     public val rows: Int,
     public val columns: Int,
-) {
+) : WithType<T> {
+
+    override val type: SafeType<T> get() = linearSpace.type
+
     public operator fun invoke(vararg elements: T): Matrix<T> {
         require(rows * columns == elements.size) { "The number of elements ${elements.size} is not equal $rows * $columns" }
         return linearSpace.buildMatrix(rows, columns) { i, j -> elements[i * columns + j] }
@@ -49,10 +55,10 @@ public inline fun <T : Any> LinearSpace<T, Ring<T>>.column(
 
 public fun <T : Any> LinearSpace<T, Ring<T>>.column(vararg values: T): Matrix<T> = column(values.size, values::get)
 
-public object SymmetricMatrixFeature : MatrixFeature
+public object Symmetric : MatrixAttribute<Unit>, FlagAttribute
 
 /**
- * Naive implementation of a symmetric matrix builder, that adds a [SymmetricMatrixFeature] tag. The resulting matrix contains
+ * Naive implementation of a symmetric matrix builder, that adds a [Symmetric] tag. The resulting matrix contains
  * full `size^2` number of elements, but caches elements during calls to save [builder] calls. [builder] is always called in the
  * upper triangle region meaning that `i <= j`
  */
@@ -60,7 +66,7 @@ public fun <T : Any, A : Ring<T>> MatrixBuilder<T, A>.symmetric(
     builder: (i: Int, j: Int) -> T,
 ): Matrix<T> {
     require(columns == rows) { "In order to build symmetric matrix, number of rows $rows should be equal to number of columns $columns" }
-    return with(BufferAccessor2D<T?>(rows, rows, MutableBuffer.Companion::boxing)) {
+    return with(BufferAccessor2D<T?>(rows, rows, MutableBufferFactory(type))) {
         val cache = factory(rows * rows) { null }
         linearSpace.buildMatrix(rows, rows) { i, j ->
             val cached = cache[i, j]
@@ -72,6 +78,6 @@ public fun <T : Any, A : Ring<T>> MatrixBuilder<T, A>.symmetric(
             } else {
                 cached
             }
-        }.withFeature(SymmetricMatrixFeature)
+        }.withAttribute(Symmetric)
     }
 }
\ No newline at end of file
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt
deleted file mode 100644
index ce7acdcba..000000000
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright 2018-2022 KMath contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package space.kscience.kmath.linear
-
-import space.kscience.kmath.nd.StructureFeature
-
-/**
- * A marker interface representing some properties of matrices or additional transformations of them. Features are used
- * to optimize matrix operations performance in some cases or retrieve the APIs.
- */
-public interface MatrixFeature: StructureFeature
-
-/**
- * Matrices with this feature are considered to have only diagonal non-null elements.
- */
-public interface DiagonalFeature : MatrixFeature {
-    public companion object : DiagonalFeature
-}
-
-/**
- * Matrices with this feature have all zero elements.
- */
-public object ZeroFeature : DiagonalFeature
-
-/**
- * Matrices with this feature have unit elements on diagonal and zero elements in all other places.
- */
-public object UnitFeature : DiagonalFeature
-
-/**
- * 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.
- */
-public interface InverseMatrixFeature<out T : Any> : MatrixFeature {
-    /**
-     * The inverse matrix of the matrix that owns this feature.
-     */
-    public val inverse: Matrix<T>
-}
-
-/**
- * Matrices with this feature can compute their determinant.
- *
- * @param T the type of matrices' items.
- */
-public interface DeterminantFeature<out T : Any> : MatrixFeature {
-    /**
-     * The determinant of the matrix that owns this feature.
-     */
-    public val determinant: T
-}
-
-/**
- * Produces a [DeterminantFeature] where the [DeterminantFeature.determinant] is [determinant].
- *
- * @param determinant the value of determinant.
- * @return a new [DeterminantFeature].
- */
-@Suppress("FunctionName")
-public fun <T : Any> DeterminantFeature(determinant: T): DeterminantFeature<T> = object : DeterminantFeature<T> {
-    override val determinant: T = determinant
-}
-
-/**
- * Matrices with this feature are lower triangular ones.
- */
-public object LFeature : MatrixFeature
-
-/**
- * Matrices with this feature are upper triangular ones.
- */
-public object UFeature : MatrixFeature
-
-/**
- * Matrices with this feature support LU factorization: *a = [l] &middot; [u]* where *a* is the owning matrix.
- *
- * @param T the type of matrices' items.
- */
-public interface LUDecompositionFeature<out T : Any> : MatrixFeature {
-    /**
-     * The lower triangular matrix in this decomposition. It may have [LFeature].
-     */
-    public val l: Matrix<T>
-
-    /**
-     * The upper triangular matrix in this decomposition. It may have [UFeature].
-     */
-    public val u: Matrix<T>
-}
-
-/**
- * Matrices with this feature support LU factorization with partial pivoting: *[p] &middot; a = [l] &middot; [u]* where
- * *a* is the owning matrix.
- *
- * @param T the type of matrices' items.
- */
-public interface LupDecompositionFeature<out T : Any> : MatrixFeature {
-    /**
-     * The lower triangular matrix in this decomposition. It may have [LFeature].
-     */
-    public val l: Matrix<T>
-
-    /**
-     * The upper triangular matrix in this decomposition. It may have [UFeature].
-     */
-    public val u: Matrix<T>
-
-    /**
-     * The permutation matrix in this decomposition.
-     */
-    public val p: Matrix<T>
-}
-
-/**
- * Matrices with this feature are orthogonal ones: *a &middot; a<sup>T</sup> = u* where *a* is the owning matrix, *u*
- * is the unit matrix ([UnitFeature]).
- */
-public object OrthogonalFeature : MatrixFeature
-
-/**
- * Matrices with this feature support QR factorization: *a = [q] &middot; [r]* where *a* is the owning matrix.
- *
- * @param T the type of matrices' items.
- */
-public interface QRDecompositionFeature<out T : Any> : MatrixFeature {
-    /**
-     * The orthogonal matrix in this decomposition. It may have [OrthogonalFeature].
-     */
-    public val q: Matrix<T>
-
-    /**
-     * The upper triangular matrix in this decomposition. It may have [UFeature].
-     */
-    public val r: Matrix<T>
-}
-
-/**
- * Matrices with this feature support Cholesky factorization: *a = [l] &middot; [l]<sup>H</sup>* where *a* is the
- * owning matrix.
- *
- * @param T the type of matrices' items.
- */
-public interface CholeskyDecompositionFeature<out T : Any> : MatrixFeature {
-    /**
-     * The triangular matrix in this decomposition. It may have either [UFeature] or [LFeature].
-     */
-    public val l: Matrix<T>
-}
-
-/**
- * Matrices with this feature support SVD: *a = [u] &middot; [s] &middot; [v]<sup>H</sup>* where *a* is the owning
- * matrix.
- *
- * @param T the type of matrices' items.
- */
-public interface SingularValueDecompositionFeature<out T : Any> : MatrixFeature {
-    /**
-     * The matrix in this decomposition. It is unitary, and it consists from left singular vectors.
-     */
-    public val u: Matrix<T>
-
-    /**
-     * The matrix in this decomposition. Its main diagonal elements are singular values.
-     */
-    public val s: Matrix<T>
-
-    /**
-     * The matrix in this decomposition. It is unitary, and it consists from right singular vectors.
-     */
-    public val v: Matrix<T>
-
-    /**
-     * The buffer of singular values of this SVD.
-     */
-    public val singularValues: Point<T>
-}
-
-//TODO add sparse matrix feature
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt
index 46454a584..a5987bb18 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt
@@ -1,35 +1,27 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.linear
 
+import space.kscience.attributes.Attribute
+import space.kscience.attributes.Attributes
+import space.kscience.attributes.withAttribute
 import space.kscience.kmath.UnstableKMathAPI
-import space.kscience.kmath.misc.FeatureSet
-import space.kscience.kmath.nd.StructureFeature
 import space.kscience.kmath.operations.Ring
-import kotlin.reflect.KClass
 
 /**
- * A [Matrix] that holds [MatrixFeature] objects.
+ * A [Matrix] that holds [MatrixAttribute] objects.
  *
  * @param T the type of items.
  */
-public class MatrixWrapper<out T : Any> internal constructor(
+public class MatrixWrapper<out T> internal constructor(
     public val origin: Matrix<T>,
-    public val features: FeatureSet<StructureFeature>,
+    override val attributes: Attributes,
 ) : Matrix<T> by origin {
 
-    /**
-     * Get the first feature matching given class. Does not guarantee that matrix has only one feature matching the
-     * criteria.
-     */
-    @Suppress("UNCHECKED_CAST")
-    override fun <F : StructureFeature> getFeature(type: KClass<out F>): F? =
-        features.getFeature(type) ?: origin.getFeature(type)
-
-    override fun toString(): String = "MatrixWrapper(matrix=$origin, features=$features)"
+    override fun toString(): String = "MatrixWrapper(matrix=$origin, features=$attributes)"
 }
 
 /**
@@ -43,52 +35,50 @@ public val <T : Any> Matrix<T>.origin: Matrix<T>
 /**
  * Add a single feature to a [Matrix]
  */
-public fun <T : Any> Matrix<T>.withFeature(newFeature: MatrixFeature): MatrixWrapper<T> = if (this is MatrixWrapper) {
-    MatrixWrapper(origin, features.with(newFeature))
+public fun <T, A : Attribute<T>> Matrix<T>.withAttribute(
+    attribute: A,
+    attrValue: T,
+): MatrixWrapper<T> = if (this is MatrixWrapper) {
+    MatrixWrapper(origin, attributes.withAttribute(attribute, attrValue))
 } else {
-    MatrixWrapper(this, FeatureSet.of(newFeature))
+    MatrixWrapper(this, Attributes(attribute, attrValue))
 }
 
-@Deprecated("To be replaced by withFeature")
-public operator fun <T : Any> Matrix<T>.plus(newFeature: MatrixFeature): MatrixWrapper<T> = withFeature(newFeature)
+public fun <T, A : Attribute<Unit>> Matrix<T>.withAttribute(
+    attribute: A,
+): MatrixWrapper<T> = if (this is MatrixWrapper) {
+    MatrixWrapper(origin, attributes.withAttribute(attribute))
+} else {
+    MatrixWrapper(this, Attributes(attribute, Unit))
+}
 
 /**
- * Add a collection of features to a [Matrix]
+ * Modify matrix attributes
  */
-public fun <T : Any> Matrix<T>.withFeatures(newFeatures: Iterable<MatrixFeature>): MatrixWrapper<T> =
+public fun <T> Matrix<T>.modifyAttributes(modifier: (Attributes) -> Attributes): MatrixWrapper<T> =
     if (this is MatrixWrapper) {
-        MatrixWrapper(origin, features.with(newFeatures))
+        MatrixWrapper(origin, modifier(attributes))
     } else {
-        MatrixWrapper(this, FeatureSet.of(newFeatures))
+        MatrixWrapper(this, modifier(Attributes.EMPTY))
     }
 
 /**
- * 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> LinearSpace<T, Ring<T>>.one(
     rows: Int,
     columns: Int,
-): Matrix<T> = VirtualMatrix(rows, columns) { i, j ->
+): MatrixWrapper<T> = VirtualMatrix(rows, columns) { i, j ->
     if (i == j) elementAlgebra.one else elementAlgebra.zero
-}.withFeature(UnitFeature)
+}.withAttribute(IsUnit)
 
 
 /**
  * A virtual matrix of zeroes
  */
-public fun <T : Any> LinearSpace<T, Ring<T>>.zero(
+public fun <T> LinearSpace<T, Ring<T>>.zero(
     rows: Int,
     columns: Int,
-): Matrix<T> = VirtualMatrix(rows, columns) { _, _ ->
+): MatrixWrapper<T> = VirtualMatrix(rows, columns) { _, _ ->
     elementAlgebra.zero
-}.withFeature(ZeroFeature)
-
-public class TransposedFeature<out T : Any>(public val original: Matrix<T>) : MatrixFeature
-
-/**
- * Create a virtual transposed matrix without copying anything. `A.transpose().transpose() === A`
- */
-@Suppress("UNCHECKED_CAST")
-@OptIn(UnstableKMathAPI::class)
-public fun <T : Any> Matrix<T>.transpose(): Matrix<T> = getFeature(TransposedFeature::class)?.original as? Matrix<T>
-    ?: VirtualMatrix(colNum, rowNum) { i, j -> get(j, i) }.withFeature(TransposedFeature(this))
+}.withAttribute(IsZero)
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/Transposed.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/Transposed.kt
new file mode 100644
index 000000000..36be711e7
--- /dev/null
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/Transposed.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2018-2023 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.linear
+
+import space.kscience.attributes.Attributes
+
+
+public class TransposedMatrix<T>(public val origin: Matrix<T>) : Matrix<T> {
+
+    override val rowNum: Int get() = origin.colNum
+
+    override val colNum: Int get() = origin.rowNum
+
+    override fun get(i: Int, j: Int): T = origin[j, i]
+
+    override val attributes: Attributes get() = Attributes.EMPTY
+}
+
+
+/**
+ * Create a virtual transposed matrix without copying anything. `A.transpose().transpose() === A`
+ */
+public fun <T> Matrix<T>.transposed(): Matrix<T> = (this as? TransposedMatrix<T>)?.origin ?: TransposedMatrix(this)
\ No newline at end of file
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt
index 55b970f4a..2b031de06 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt
@@ -1,10 +1,11 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.linear
 
+import space.kscience.attributes.Attributes
 import space.kscience.kmath.nd.ShapeND
 
 
@@ -13,9 +14,10 @@ import space.kscience.kmath.nd.ShapeND
  *
  * @property generator the function that provides elements.
  */
-public class VirtualMatrix<out T : Any>(
+public class VirtualMatrix<out T>(
     override val rowNum: Int,
     override val colNum: Int,
+    override val attributes: Attributes = Attributes.EMPTY,
     public val generator: (i: Int, j: Int) -> T,
 ) : Matrix<T> {
 
@@ -24,5 +26,7 @@ public class VirtualMatrix<out T : Any>(
     override operator fun get(i: Int, j: Int): T = generator(i, j)
 }
 
-public fun <T : Any> MatrixBuilder<T, *>.virtual(generator: (i: Int, j: Int) -> T): VirtualMatrix<T> =
-    VirtualMatrix(rows, columns, generator)
+public fun <T : Any> MatrixBuilder<T, *>.virtual(
+    attributes: Attributes = Attributes.EMPTY,
+    generator: (i: Int, j: Int) -> T,
+): VirtualMatrix<T> = VirtualMatrix(rows, columns, attributes, generator)
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/matrixAttributes.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/matrixAttributes.kt
new file mode 100644
index 000000000..dadb2f3d7
--- /dev/null
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/matrixAttributes.kt
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2018-2022 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+@file:Suppress("UnusedReceiverParameter")
+
+package space.kscience.kmath.linear
+
+import space.kscience.attributes.*
+import space.kscience.kmath.nd.StructureAttribute
+
+
+/**
+ * A marker interface for algebras that operate on matrices
+ * @param T type of matrix element
+ */
+public interface MatrixScope<T> : AttributeScope<Matrix<T>>, WithType<T>
+
+/**
+ * A marker interface representing some properties of matrices or additional transformations of them. Features are used
+ * to optimize matrix operations performance in some cases or retrieve the APIs.
+ */
+public interface MatrixAttribute<T> : StructureAttribute<T>
+
+/**
+ * Matrices with this feature are considered to have only diagonal non-zero elements.
+ */
+public interface IsDiagonal : MatrixAttribute<Unit>, FlagAttribute {
+    public companion object : IsDiagonal
+}
+
+/**
+ * Matrices with this feature have all zero elements.
+ */
+public object IsZero : IsDiagonal
+
+/**
+ * Matrices with this feature have unit elements on diagonal and zero elements in all other places.
+ */
+public object IsUnit : IsDiagonal
+
+/**
+ * Matrices with this feature can be inverted.
+ *
+ * @param T the type of matrices' items.
+ */
+public class Inverted<T>() :
+    PolymorphicAttribute<Matrix<T>>(safeTypeOf()),
+    MatrixAttribute<Matrix<T>>
+
+public val <T> MatrixScope<T>.Inverted: Inverted<T> get() = Inverted()
+
+/**
+ * Matrices with this feature can compute their determinant.
+ *
+ * @param T the type of matrices' items.
+ */
+public class Determinant<T>(type: SafeType<T>) :
+    PolymorphicAttribute<T>(type),
+    MatrixAttribute<T>
+
+public val <T> MatrixScope<T>.Determinant: Determinant<T> get() = Determinant(type)
+
+/**
+ * Matrices with this feature are lower triangular ones.
+ */
+public object LowerTriangular : MatrixAttribute<Unit>, FlagAttribute
+
+/**
+ * Matrices with this feature are upper triangular ones.
+ */
+public object UpperTriangular : MatrixAttribute<Unit>, FlagAttribute
+
+/**
+ * Matrices with this feature support LU factorization: *a = [l] &middot; [u]* where *a* is the owning matrix.
+ * @param l The lower triangular matrix in this decomposition. It may have [LowerTriangular].
+ * @param u The upper triangular matrix in this decomposition. It may have [UpperTriangular].
+ */
+public data class LUDecomposition<T>(val l: Matrix<T>, val u: Matrix<T>)
+
+/**
+ * Matrices with this feature support LU factorization: *a = [l] &middot; [u]* where *a* is the owning matrix.
+ *
+ * @param T the type of matrices' items.
+ */
+public class LuDecompositionAttribute<T> :
+    PolymorphicAttribute<LUDecomposition<T>>(safeTypeOf()),
+    MatrixAttribute<LUDecomposition<T>>
+
+public val <T> MatrixScope<T>.LU: LuDecompositionAttribute<T> get() = LuDecompositionAttribute()
+
+
+/**
+ * Matrices with this feature are orthogonal ones: *a &middot; a<sup>T</sup> = u* where *a* is the owning matrix, *u*
+ * is the unit matrix ([IsUnit]).
+ */
+public object OrthogonalAttribute : MatrixAttribute<Unit>, FlagAttribute
+
+
+public interface QRDecomposition<out T> {
+    /**
+     * The orthogonal matrix in this decomposition. It may have [OrthogonalAttribute].
+     */
+    public val q: Matrix<T>
+
+    /**
+     * The upper triangular matrix in this decomposition. It may have [UpperTriangular].
+     */
+    public val r: Matrix<T>
+}
+
+/**
+ * Matrices with this feature support QR factorization: *a = [QR.q] &middot; [QR.r]* where *a* is the owning matrix.
+ *
+ * @param T the type of matrices' items.
+ */
+public class QRDecompositionAttribute<T>() :
+    PolymorphicAttribute<QRDecomposition<T>>(safeTypeOf()),
+    MatrixAttribute<QRDecomposition<T>>
+
+public val <T> MatrixScope<T>.QR: QRDecompositionAttribute<T>
+    get() = QRDecompositionAttribute()
+
+public interface CholeskyDecomposition<T> {
+    /**
+     * The triangular matrix in this decomposition. It may have either [UpperTriangular] or [LowerTriangular].
+     */
+    public val l: Matrix<T>
+}
+
+/**
+ * Matrices with this feature support Cholesky factorization: *a = [l] &middot; [l]<sup>H</sup>* where *a* is the
+ * owning matrix.
+ *
+ * @param T the type of matrices' items.
+ */
+public class CholeskyDecompositionAttribute<T> :
+    PolymorphicAttribute<CholeskyDecomposition<T>>(safeTypeOf()),
+    MatrixAttribute<CholeskyDecomposition<T>>
+
+public val <T> MatrixScope<T>.Cholesky: CholeskyDecompositionAttribute<T>
+    get() = CholeskyDecompositionAttribute()
+
+public interface SingularValueDecomposition<T> {
+    /**
+     * The matrix in this decomposition. It is unitary, and it consists of left singular vectors.
+     */
+    public val u: Matrix<T>
+
+    /**
+     * The matrix in this decomposition. Its main diagonal elements are singular values.
+     */
+    public val s: Matrix<T>
+
+    /**
+     * The matrix in this decomposition. It is unitary, and it consists of right singular vectors.
+     */
+    public val v: Matrix<T>
+
+    /**
+     * The buffer of singular values for this SVD.
+     */
+    public val singularValues: Point<T>
+}
+
+/**
+ * Matrices with this feature support SVD: *a = [u] &middot; [s] &middot; [v]<sup>H</sup>* where *a* is the owning
+ * matrix.
+ *
+ * @param T the type of matrices' items.
+ */
+public class SVDAttribute<T>() :
+    PolymorphicAttribute<SingularValueDecomposition<T>>(safeTypeOf()),
+    MatrixAttribute<SingularValueDecomposition<T>>
+
+public val <T> MatrixScope<T>.SVD: SVDAttribute<T> get() = SVDAttribute()
+
+
+//TODO add sparse matrix feature
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt
deleted file mode 100644
index bdda674dc..000000000
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2018-2022 KMath contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package space.kscience.kmath.misc
-
-import kotlin.jvm.JvmInline
-import kotlin.reflect.KClass
-
-/**
- * An entity that contains a set of features defined by their types
- */
-public interface Featured<F : Any> {
-    public fun <T : F> getFeature(type: FeatureKey<T>): T?
-}
-
-public typealias FeatureKey<T> = KClass<out T>
-
-public interface Feature<F : Feature<F>> {
-
-    /**
-     * A key used for extraction
-     */
-    @Suppress("UNCHECKED_CAST")
-    public val key: FeatureKey<F>
-        get() = this::class as FeatureKey<F>
-}
-
-/**
- * A container for a set of features
- */
-@JvmInline
-public value class FeatureSet<F : Feature<F>> private constructor(public val features: Map<FeatureKey<F>, F>) : Featured<F> {
-    @Suppress("UNCHECKED_CAST")
-    override fun <T : F> getFeature(type: FeatureKey<T>): T? = features[type]?.let { it as T }
-
-    public inline fun <reified T : F> getFeature(): T? = getFeature(T::class)
-
-    public fun <T : F> with(feature: T, type: FeatureKey<F> = feature.key): FeatureSet<F> =
-        FeatureSet(features + (type to feature))
-
-    public fun with(other: FeatureSet<F>): FeatureSet<F> = FeatureSet(features + other.features)
-
-    public fun with(vararg otherFeatures: F): FeatureSet<F> =
-        FeatureSet(features + otherFeatures.associateBy { it.key })
-
-    public fun with(otherFeatures: Iterable<F>): FeatureSet<F> =
-        FeatureSet(features + otherFeatures.associateBy { it.key })
-
-    public operator fun iterator(): Iterator<F> = features.values.iterator()
-
-    override fun toString(): String = features.values.joinToString(prefix = "[ ", postfix = " ]")
-
-
-    public companion object {
-        public fun <F : Feature<F>> of(vararg features: F): FeatureSet<F> = FeatureSet(features.associateBy { it.key })
-        public fun <F : Feature<F>> of(features: Iterable<F>): FeatureSet<F> =
-            FeatureSet(features.associateBy { it.key })
-    }
-}
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/collections.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/collections.kt
index f630055fa..6227e2f45 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/collections.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/collections.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2023 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt
index c05f1a6a9..60f71b943 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt
index c7886469f..9655e1139 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt
index 77ef07ea8..cc43c84bc 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt
index 31b8c0037..e1b24dd68 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt
@@ -1,9 +1,11 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 
+@file:OptIn(UnstableKMathAPI::class)
+
 package space.kscience.kmath.misc
 
 import space.kscience.kmath.UnstableKMathAPI
@@ -22,7 +24,6 @@ public fun <V : Comparable<V>> Buffer<V>.indicesSorted(): IntArray = permSortInd
 /**
  * Create a zero-copy virtual buffer that contains the same elements but in ascending order
  */
-@OptIn(UnstableKMathAPI::class)
 public fun <V : Comparable<V>> Buffer<V>.sorted(): Buffer<V> {
     val permutations = indicesSorted()
     return VirtualBuffer(size) { this[permutations[it]] }
@@ -35,7 +36,6 @@ public fun <V : Comparable<V>> Buffer<V>.indicesSortedDescending(): IntArray =
 /**
  * Create a zero-copy virtual buffer that contains the same elements but in descending order
  */
-@OptIn(UnstableKMathAPI::class)
 public fun <V : Comparable<V>> Buffer<V>.sortedDescending(): Buffer<V> {
     val permutations = indicesSortedDescending()
     return VirtualBuffer(size) { this[permutations[it]] }
@@ -45,7 +45,6 @@ public fun <V : Comparable<V>> Buffer<V>.sortedDescending(): Buffer<V> {
 public fun <V, C : Comparable<C>> Buffer<V>.indicesSortedBy(selector: (V) -> C): IntArray =
     permSortIndicesWith(compareBy { selector(get(it)) })
 
-@OptIn(UnstableKMathAPI::class)
 public fun <V, C : Comparable<C>> Buffer<V>.sortedBy(selector: (V) -> C): Buffer<V> {
     val permutations = indicesSortedBy(selector)
     return VirtualBuffer(size) { this[permutations[it]] }
@@ -55,7 +54,6 @@ public fun <V, C : Comparable<C>> Buffer<V>.sortedBy(selector: (V) -> C): Buffer
 public fun <V, C : Comparable<C>> Buffer<V>.indicesSortedByDescending(selector: (V) -> C): IntArray =
     permSortIndicesWith(compareByDescending { selector(get(it)) })
 
-@OptIn(UnstableKMathAPI::class)
 public fun <V, C : Comparable<C>> Buffer<V>.sortedByDescending(selector: (V) -> C): Buffer<V> {
     val permutations = indicesSortedByDescending(selector)
     return VirtualBuffer(size) { this[permutations[it]] }
@@ -65,6 +63,14 @@ public fun <V, C : Comparable<C>> Buffer<V>.sortedByDescending(selector: (V) ->
 public fun <V> Buffer<V>.indicesSortedWith(comparator: Comparator<V>): IntArray =
     permSortIndicesWith { i1, i2 -> comparator.compare(get(i1), get(i2)) }
 
+/**
+ * Create virtual zero-copy buffer with elements sorted by [comparator]
+ */
+public fun <V> Buffer<V>.sortedWith(comparator: Comparator<V>): Buffer<V> {
+    val permutations = indicesSortedWith(comparator)
+    return VirtualBuffer(size) { this[permutations[it]] }
+}
+
 private fun <V> Buffer<V>.permSortIndicesWith(comparator: Comparator<Int>): IntArray {
     if (size < 2) return IntArray(size) { 0 }
 
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt
index 91e26cc1b..744f760f3 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,7 +8,7 @@ package space.kscience.kmath.nd
 import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.operations.*
-import kotlin.reflect.KClass
+import space.kscience.kmath.structures.MutableBufferFactory
 
 /**
  * The base interface for all ND-algebra implementations.
@@ -16,16 +16,22 @@ import kotlin.reflect.KClass
  * @param T the type of ND-structure element.
  * @param C the type of the element context.
  */
-public interface AlgebraND<T, out C : Algebra<T>>: Algebra<StructureND<T>> {
+public interface AlgebraND<T, out C : Algebra<T>> : Algebra<StructureND<T>> {
     /**
      * The algebra over elements of ND structure.
      */
     public val elementAlgebra: C
 
+    /**
+     * Produces a new [MutableStructureND] using given initializer function.
+     */
+    public fun mutableStructureND(shape: ShapeND, initializer: C.(IntArray) -> T): MutableStructureND<T>
+
     /**
      * Produces a new [StructureND] using given initializer function.
      */
-    public fun structureND(shape: ShapeND, initializer: C.(IntArray) -> T): StructureND<T>
+    public fun structureND(shape: ShapeND, initializer: C.(IntArray) -> T): StructureND<T> =
+        mutableStructureND(shape, initializer)
 
     /**
      * Maps elements from one structure to another one by applying [transform] to them.
@@ -65,31 +71,19 @@ public interface AlgebraND<T, out C : Algebra<T>>: Algebra<StructureND<T>> {
         structure.map { value -> this@invoke(value) }
 
     /**
-     * Get a feature of the structure in this scope. Structure features take precedence other context features.
+     * Get an attribute value for the structure in this scope. Structure features take precedence other context features.
      *
-     * @param F the type of feature.
      * @param structure the structure.
-     * @param type the [KClass] instance of [F].
+     * @param attribute to be computed.
      * @return a feature object or `null` if it isn't present.
      */
     @UnstableKMathAPI
-    public fun <F : StructureFeature> getFeature(structure: StructureND<T>, type: KClass<out F>): F? =
-        structure.getFeature(type)
+    public fun <T, A : StructureAttribute<T>> attributeFor(structure: StructureND<*>, attribute: A): T? =
+        structure.attributes[attribute]
 
     public companion object
 }
 
-/**
- * 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 F the type of feature.
- * @return a feature object or `null` if it isn't present.
- */
-@UnstableKMathAPI
-public inline fun <T : Any, reified F : StructureFeature> AlgebraND<T, *>.getFeature(structure: StructureND<T>): F? =
-    getFeature(structure, F::class)
-
 /**
  * Space of [StructureND].
  *
@@ -97,6 +91,8 @@ public inline fun <T : Any, reified F : StructureFeature> AlgebraND<T, *>.getFea
  * @param A the type of group over structure elements.
  */
 public interface GroupOpsND<T, out A : GroupOps<T>> : GroupOps<StructureND<T>>, AlgebraND<T, A> {
+    override val bufferFactory: MutableBufferFactory<StructureND<T>> get() = MutableBufferFactory<StructureND<T>>()
+
     /**
      * Element-wise addition.
      *
@@ -108,7 +104,7 @@ public interface GroupOpsND<T, out A : GroupOps<T>> : GroupOps<StructureND<T>>,
     override fun add(left: StructureND<T>, right: StructureND<T>): StructureND<T> =
         zip(left, right) { aValue, bValue -> add(aValue, bValue) }
 
-    // TODO move to extensions after KEEP-176
+    // TODO implement using context receivers
 
     /**
      * Adds an ND structure to an element of it.
@@ -175,8 +171,6 @@ public interface RingOpsND<T, out A : RingOps<T>> : RingOps<StructureND<T>>, Gro
     override fun multiply(left: StructureND<T>, right: StructureND<T>): StructureND<T> =
         zip(left, right) { aValue, bValue -> multiply(aValue, bValue) }
 
-    //TODO move to extensions with context receivers
-
     /**
      * Multiplies an ND structure by an element of it.
      *
@@ -226,7 +220,6 @@ public interface FieldOpsND<T, out A : Field<T>> :
     override fun divide(left: StructureND<T>, right: StructureND<T>): StructureND<T> =
         zip(left, right) { aValue, bValue -> divide(aValue, bValue) }
 
-    //TODO move to extensions after https://github.com/Kotlin/KEEP/blob/master/proposals/context-receivers.md
     /**
      * Divides an ND structure by an element of it.
      *
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt
index 74c63e6e2..a99df4c1f 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,6 +7,8 @@
 
 package space.kscience.kmath.nd
 
+import space.kscience.attributes.SafeType
+import space.kscience.attributes.safeTypeOf
 import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.operations.*
@@ -16,9 +18,10 @@ public interface BufferAlgebraND<T, out A : Algebra<T>> : AlgebraND<T, A> {
     public val bufferAlgebra: BufferAlgebra<T, A>
     override val elementAlgebra: A get() = bufferAlgebra.elementAlgebra
 
-    override fun structureND(shape: ShapeND, initializer: A.(IntArray) -> T): BufferND<T> {
+    //TODO change AlgebraND contract to include this
+    override fun mutableStructureND(shape: ShapeND, initializer: A.(IntArray) -> T): MutableBufferND<T> {
         val indexer = indexerBuilder(shape)
-        return BufferND(
+        return MutableBufferND(
             indexer,
             bufferAlgebra.buffer(indexer.linearSize) { offset ->
                 elementAlgebra.initializer(indexer.index(offset))
@@ -26,6 +29,9 @@ public interface BufferAlgebraND<T, out A : Algebra<T>> : AlgebraND<T, A> {
         )
     }
 
+    override fun structureND(shape: ShapeND, initializer: A.(IntArray) -> T): BufferND<T> =
+        mutableStructureND(shape, initializer)
+
     @OptIn(PerformancePitfall::class)
     public fun StructureND<T>.toBufferND(): BufferND<T> = when (this) {
         is BufferND -> this
@@ -101,6 +107,9 @@ public open class BufferedGroupNDOps<T, out A : Group<T>>(
     override val bufferAlgebra: BufferAlgebra<T, A>,
     override val indexerBuilder: (ShapeND) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder,
 ) : GroupOpsND<T, A>, BufferAlgebraND<T, A> {
+
+    override val type: SafeType<StructureND<T>> get() = safeTypeOf<StructureND<T>>()
+
     override fun StructureND<T>.unaryMinus(): StructureND<T> = map { -it }
 }
 
@@ -133,6 +142,11 @@ public fun <T, A : Algebra<T>> BufferAlgebraND<T, A>.structureND(
     initializer: A.(IntArray) -> T,
 ): BufferND<T> = structureND(ShapeND(shape), initializer)
 
+public fun <T, A : Algebra<T>> BufferAlgebraND<T, A>.mutableStructureND(
+    vararg shape: Int,
+    initializer: A.(IntArray) -> T,
+): MutableBufferND<T> = mutableStructureND(ShapeND(shape), initializer)
+
 public fun <T, EA : Algebra<T>, A> A.structureND(
     initializer: EA.(IntArray) -> T,
 ): BufferND<T> where A : BufferAlgebraND<T, EA>, A : WithShape = structureND(shape, initializer)
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt
index 9217f6fdc..5746ff881 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -34,10 +34,10 @@ public open class BufferND<out T>(
 /**
  * Create a generic [BufferND] using provided [initializer]
  */
-public fun <T> BufferND(
+public inline fun <reified T> BufferND(
     shape: ShapeND,
-    bufferFactory: BufferFactory<T> = BufferFactory.boxing(),
-    initializer: (IntArray) -> T,
+    bufferFactory: BufferFactory<T> = BufferFactory<T>(),
+    crossinline initializer: (IntArray) -> T,
 ): BufferND<T> {
     val strides = Strides(shape)
     return BufferND(strides, bufferFactory(strides.linearSize) { initializer(strides.index(it)) })
@@ -84,10 +84,10 @@ public open class MutableBufferND<T>(
 /**
  * Create a generic [BufferND] using provided [initializer]
  */
-public fun <T> MutableBufferND(
+public inline fun <reified T> MutableBufferND(
     shape: ShapeND,
-    bufferFactory: MutableBufferFactory<T> = MutableBufferFactory.boxing(),
-    initializer: (IntArray) -> T,
+    bufferFactory: MutableBufferFactory<T> = MutableBufferFactory(),
+    crossinline initializer: (IntArray) -> T,
 ): MutableBufferND<T> {
     val strides = Strides(shape)
     return MutableBufferND(strides, bufferFactory(strides.linearSize) { initializer(strides.index(it)) })
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Float64FieldND.kt
similarity index 52%
rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt
rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Float64FieldND.kt
index 265d1eec8..4bb853af8 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Float64FieldND.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,7 +8,7 @@ package space.kscience.kmath.nd
 import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.operations.*
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import kotlin.contracts.InvocationKind
 import kotlin.contracts.contract
 import kotlin.math.pow
@@ -17,10 +17,11 @@ import kotlin.math.pow as kpow
 /**
  * A simple mutable [StructureND] of doubles
  */
-public class DoubleBufferND(
+public class Float64BufferND(
     indexes: ShapeIndexer,
-    override val buffer: DoubleBuffer,
-) : MutableBufferND<Double>(indexes, buffer), MutableStructureNDOfDouble{
+    override val buffer: Float64Buffer,
+) : MutableBufferND<Double>(indexes, buffer), MutableStructureNDOfDouble {
+
     override fun getDouble(index: IntArray): Double = buffer[indices.offset(index)]
 
     override fun setDouble(index: IntArray, value: Double) {
@@ -29,101 +30,101 @@ public class DoubleBufferND(
 }
 
 
-public sealed class DoubleFieldOpsND : BufferedFieldOpsND<Double, DoubleField>(DoubleField.bufferAlgebra),
+public sealed class Floa64FieldOpsND : BufferedFieldOpsND<Double, Float64Field>(Float64Field.bufferAlgebra),
     ScaleOperations<StructureND<Double>>, ExtendedFieldOps<StructureND<Double>> {
 
     @OptIn(PerformancePitfall::class)
-    override fun StructureND<Double>.toBufferND(): DoubleBufferND = when (this) {
-        is DoubleBufferND -> this
+    override fun StructureND<Double>.toBufferND(): Float64BufferND = when (this) {
+        is Float64BufferND -> this
         else -> {
             val indexer = indexerBuilder(shape)
-            DoubleBufferND(indexer, DoubleBuffer(indexer.linearSize) { offset -> get(indexer.index(offset)) })
+            Float64BufferND(indexer, Float64Buffer(indexer.linearSize) { offset -> get(indexer.index(offset)) })
         }
     }
 
     protected inline fun mapInline(
-        arg: DoubleBufferND,
+        arg: Float64BufferND,
         transform: (Double) -> Double,
-    ): DoubleBufferND {
+    ): Float64BufferND {
         val indexes = arg.indices
         val array = arg.buffer.array
-        return DoubleBufferND(indexes, DoubleBuffer(indexes.linearSize) { transform(array[it]) })
+        return Float64BufferND(indexes, Float64Buffer(indexes.linearSize) { transform(array[it]) })
     }
 
     private inline fun zipInline(
-        l: DoubleBufferND,
-        r: DoubleBufferND,
+        l: Float64BufferND,
+        r: Float64BufferND,
         block: (l: Double, r: Double) -> Double,
-    ): DoubleBufferND {
+    ): Float64BufferND {
         require(l.indices == r.indices) { "Zip requires the same shapes, but found ${l.shape} on the left and ${r.shape} on the right" }
         val indexes = l.indices
         val lArray = l.buffer.array
         val rArray = r.buffer.array
-        return DoubleBufferND(indexes, DoubleBuffer(indexes.linearSize) { block(lArray[it], rArray[it]) })
+        return Float64BufferND(indexes, Float64Buffer(indexes.linearSize) { block(lArray[it], rArray[it]) })
     }
 
     @OptIn(PerformancePitfall::class)
-    override fun StructureND<Double>.map(transform: DoubleField.(Double) -> Double): BufferND<Double> =
-        mapInline(toBufferND()) { DoubleField.transform(it) }
+    override fun StructureND<Double>.map(transform: Float64Field.(Double) -> Double): BufferND<Double> =
+        mapInline(toBufferND()) { Float64Field.transform(it) }
 
 
     @OptIn(PerformancePitfall::class)
     override fun zip(
         left: StructureND<Double>,
         right: StructureND<Double>,
-        transform: DoubleField.(Double, Double) -> Double,
-    ): BufferND<Double> = zipInline(left.toBufferND(), right.toBufferND()) { l, r -> DoubleField.transform(l, r) }
+        transform: Float64Field.(Double, Double) -> Double,
+    ): BufferND<Double> = zipInline(left.toBufferND(), right.toBufferND()) { l, r -> Float64Field.transform(l, r) }
 
-    override fun structureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): DoubleBufferND {
+    override fun mutableStructureND(shape: ShapeND, initializer: Float64Field.(IntArray) -> Double): Float64BufferND {
         val indexer = indexerBuilder(shape)
-        return DoubleBufferND(
+        return Float64BufferND(
             indexer,
-            DoubleBuffer(indexer.linearSize) { offset ->
+            Float64Buffer(indexer.linearSize) { offset ->
                 elementAlgebra.initializer(indexer.index(offset))
             }
         )
     }
 
-    override fun add(left: StructureND<Double>, right: StructureND<Double>): DoubleBufferND =
+    override fun add(left: StructureND<Double>, right: StructureND<Double>): Float64BufferND =
         zipInline(left.toBufferND(), right.toBufferND()) { l, r -> l + r }
 
-    override fun multiply(left: StructureND<Double>, right: StructureND<Double>): DoubleBufferND =
+    override fun multiply(left: StructureND<Double>, right: StructureND<Double>): Float64BufferND =
         zipInline(left.toBufferND(), right.toBufferND()) { l, r -> l * r }
 
-    override fun StructureND<Double>.unaryMinus(): DoubleBufferND = mapInline(toBufferND()) { -it }
+    override fun StructureND<Double>.unaryMinus(): Float64BufferND = mapInline(toBufferND()) { -it }
 
-    override fun StructureND<Double>.div(arg: StructureND<Double>): DoubleBufferND =
+    override fun StructureND<Double>.div(arg: StructureND<Double>): Float64BufferND =
         zipInline(toBufferND(), arg.toBufferND()) { l, r -> l / r }
 
-    override fun divide(left: StructureND<Double>, right: StructureND<Double>): DoubleBufferND =
+    override fun divide(left: StructureND<Double>, right: StructureND<Double>): Float64BufferND =
         zipInline(left.toBufferND(), right.toBufferND()) { l: Double, r: Double -> l / r }
 
-    override fun StructureND<Double>.div(arg: Double): DoubleBufferND =
+    override fun StructureND<Double>.div(arg: Double): Float64BufferND =
         mapInline(toBufferND()) { it / arg }
 
-    override fun Double.div(arg: StructureND<Double>): DoubleBufferND =
+    override fun Double.div(arg: StructureND<Double>): Float64BufferND =
         mapInline(arg.toBufferND()) { this / it }
 
-    override fun StructureND<Double>.unaryPlus(): DoubleBufferND = toBufferND()
+    override fun StructureND<Double>.unaryPlus(): Float64BufferND = toBufferND()
 
-    override fun StructureND<Double>.plus(arg: StructureND<Double>): DoubleBufferND =
+    override fun StructureND<Double>.plus(arg: StructureND<Double>): Float64BufferND =
         zipInline(toBufferND(), arg.toBufferND()) { l: Double, r: Double -> l + r }
 
-    override fun StructureND<Double>.minus(arg: StructureND<Double>): DoubleBufferND =
+    override fun StructureND<Double>.minus(arg: StructureND<Double>): Float64BufferND =
         zipInline(toBufferND(), arg.toBufferND()) { l: Double, r: Double -> l - r }
 
-    override fun StructureND<Double>.times(arg: StructureND<Double>): DoubleBufferND =
+    override fun StructureND<Double>.times(arg: StructureND<Double>): Float64BufferND =
         zipInline(toBufferND(), arg.toBufferND()) { l: Double, r: Double -> l * r }
 
-    override fun StructureND<Double>.times(k: Number): DoubleBufferND =
+    override fun StructureND<Double>.times(k: Number): Float64BufferND =
         mapInline(toBufferND()) { it * k.toDouble() }
 
-    override fun StructureND<Double>.div(k: Number): DoubleBufferND =
+    override fun StructureND<Double>.div(k: Number): Float64BufferND =
         mapInline(toBufferND()) { it / k.toDouble() }
 
-    override fun Number.times(arg: StructureND<Double>): DoubleBufferND = arg * this
+    override fun Number.times(arg: StructureND<Double>): Float64BufferND = arg * this
 
-    override fun StructureND<Double>.plus(arg: Double): DoubleBufferND = mapInline(toBufferND()) { it + arg }
+    override fun StructureND<Double>.plus(arg: Double): Float64BufferND = mapInline(toBufferND()) { it + arg }
 
     override fun StructureND<Double>.minus(arg: Double): StructureND<Double> = mapInline(toBufferND()) { it - arg }
 
@@ -131,49 +132,49 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND<Double, DoubleField>(D
 
     override fun Double.minus(arg: StructureND<Double>): StructureND<Double> = mapInline(arg.toBufferND()) { this - it }
 
-    override fun scale(a: StructureND<Double>, value: Double): DoubleBufferND =
+    override fun scale(a: StructureND<Double>, value: Double): Float64BufferND =
         mapInline(a.toBufferND()) { it * value }
 
-    override fun exp(arg: StructureND<Double>): DoubleBufferND =
+    override fun exp(arg: StructureND<Double>): Float64BufferND =
         mapInline(arg.toBufferND()) { kotlin.math.exp(it) }
 
-    override fun ln(arg: StructureND<Double>): DoubleBufferND =
+    override fun ln(arg: StructureND<Double>): Float64BufferND =
         mapInline(arg.toBufferND()) { kotlin.math.ln(it) }
 
-    override fun sin(arg: StructureND<Double>): DoubleBufferND =
+    override fun sin(arg: StructureND<Double>): Float64BufferND =
         mapInline(arg.toBufferND()) { kotlin.math.sin(it) }
 
-    override fun cos(arg: StructureND<Double>): DoubleBufferND =
+    override fun cos(arg: StructureND<Double>): Float64BufferND =
         mapInline(arg.toBufferND()) { kotlin.math.cos(it) }
 
-    override fun tan(arg: StructureND<Double>): DoubleBufferND =
+    override fun tan(arg: StructureND<Double>): Float64BufferND =
         mapInline(arg.toBufferND()) { kotlin.math.tan(it) }
 
-    override fun asin(arg: StructureND<Double>): DoubleBufferND =
+    override fun asin(arg: StructureND<Double>): Float64BufferND =
         mapInline(arg.toBufferND()) { kotlin.math.asin(it) }
 
-    override fun acos(arg: StructureND<Double>): DoubleBufferND =
+    override fun acos(arg: StructureND<Double>): Float64BufferND =
         mapInline(arg.toBufferND()) { kotlin.math.acos(it) }
 
-    override fun atan(arg: StructureND<Double>): DoubleBufferND =
+    override fun atan(arg: StructureND<Double>): Float64BufferND =
         mapInline(arg.toBufferND()) { kotlin.math.atan(it) }
 
-    override fun sinh(arg: StructureND<Double>): DoubleBufferND =
+    override fun sinh(arg: StructureND<Double>): Float64BufferND =
         mapInline(arg.toBufferND()) { kotlin.math.sinh(it) }
 
-    override fun cosh(arg: StructureND<Double>): DoubleBufferND =
+    override fun cosh(arg: StructureND<Double>): Float64BufferND =
         mapInline(arg.toBufferND()) { kotlin.math.cosh(it) }
 
-    override fun tanh(arg: StructureND<Double>): DoubleBufferND =
+    override fun tanh(arg: StructureND<Double>): Float64BufferND =
         mapInline(arg.toBufferND()) { kotlin.math.tanh(it) }
 
-    override fun asinh(arg: StructureND<Double>): DoubleBufferND =
+    override fun asinh(arg: StructureND<Double>): Float64BufferND =
         mapInline(arg.toBufferND()) { kotlin.math.asinh(it) }
 
-    override fun acosh(arg: StructureND<Double>): DoubleBufferND =
+    override fun acosh(arg: StructureND<Double>): Float64BufferND =
         mapInline(arg.toBufferND()) { kotlin.math.acosh(it) }
 
-    override fun atanh(arg: StructureND<Double>): DoubleBufferND =
+    override fun atanh(arg: StructureND<Double>): Float64BufferND =
         mapInline(arg.toBufferND()) { kotlin.math.atanh(it) }
 
     override fun power(
@@ -185,23 +186,23 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND<Double, DoubleField>(D
         mapInline(arg.toBufferND()) { it.pow(pow.toDouble()) }
     }
 
-    public companion object : DoubleFieldOpsND()
+    public companion object : Floa64FieldOpsND()
 }
 
 @OptIn(UnstableKMathAPI::class)
-public class DoubleFieldND(override val shape: ShapeND) :
-    DoubleFieldOpsND(), FieldND<Double, DoubleField>, NumbersAddOps<StructureND<Double>>,
+public class Float64FieldND(override val shape: ShapeND) :
+    Floa64FieldOpsND(), FieldND<Double, Float64Field>, NumbersAddOps<StructureND<Double>>,
     ExtendedField<StructureND<Double>> {
 
-    override fun power(arg: StructureND<Double>, pow: UInt): DoubleBufferND = mapInline(arg.toBufferND()) {
+    override fun power(arg: StructureND<Double>, pow: UInt): Float64BufferND = mapInline(arg.toBufferND()) {
         it.kpow(pow.toInt())
     }
 
-    override fun power(arg: StructureND<Double>, pow: Int): DoubleBufferND = mapInline(arg.toBufferND()) {
+    override fun power(arg: StructureND<Double>, pow: Int): Float64BufferND = mapInline(arg.toBufferND()) {
         it.kpow(pow)
     }
 
-    override fun power(arg: StructureND<Double>, pow: Number): DoubleBufferND = if (pow.isInteger()) {
+    override fun power(arg: StructureND<Double>, pow: Number): Float64BufferND = if (pow.isInteger()) {
         power(arg, pow.toInt())
     } else {
         val dpow = pow.toDouble()
@@ -211,34 +212,34 @@ public class DoubleFieldND(override val shape: ShapeND) :
         }
     }
 
-    override fun sinh(arg: StructureND<Double>): DoubleBufferND = super<DoubleFieldOpsND>.sinh(arg)
+    override fun sinh(arg: StructureND<Double>): Float64BufferND = super<Floa64FieldOpsND>.sinh(arg)
 
-    override fun cosh(arg: StructureND<Double>): DoubleBufferND = super<DoubleFieldOpsND>.cosh(arg)
+    override fun cosh(arg: StructureND<Double>): Float64BufferND = super<Floa64FieldOpsND>.cosh(arg)
 
-    override fun tanh(arg: StructureND<Double>): DoubleBufferND = super<DoubleFieldOpsND>.tan(arg)
+    override fun tanh(arg: StructureND<Double>): Float64BufferND = super<Floa64FieldOpsND>.tan(arg)
 
-    override fun asinh(arg: StructureND<Double>): DoubleBufferND = super<DoubleFieldOpsND>.asinh(arg)
+    override fun asinh(arg: StructureND<Double>): Float64BufferND = super<Floa64FieldOpsND>.asinh(arg)
 
-    override fun acosh(arg: StructureND<Double>): DoubleBufferND = super<DoubleFieldOpsND>.acosh(arg)
+    override fun acosh(arg: StructureND<Double>): Float64BufferND = super<Floa64FieldOpsND>.acosh(arg)
 
-    override fun atanh(arg: StructureND<Double>): DoubleBufferND = super<DoubleFieldOpsND>.atanh(arg)
+    override fun atanh(arg: StructureND<Double>): Float64BufferND = super<Floa64FieldOpsND>.atanh(arg)
 
-    override fun number(value: Number): DoubleBufferND {
+    override fun number(value: Number): Float64BufferND {
         val d = value.toDouble() // minimize conversions
-        return structureND(shape) { d }
+        return mutableStructureND(shape) { d }
     }
 }
 
-public val DoubleField.ndAlgebra: DoubleFieldOpsND get() = DoubleFieldOpsND
+public val Float64Field.ndAlgebra: Floa64FieldOpsND get() = Floa64FieldOpsND
 
-public fun DoubleField.ndAlgebra(vararg shape: Int): DoubleFieldND = DoubleFieldND(ShapeND(shape))
-public fun DoubleField.ndAlgebra(shape: ShapeND): DoubleFieldND = DoubleFieldND(shape)
+public fun Float64Field.ndAlgebra(vararg shape: Int): Float64FieldND = Float64FieldND(ShapeND(shape))
+public fun Float64Field.ndAlgebra(shape: ShapeND): Float64FieldND = Float64FieldND(shape)
 
 /**
  * Produce a context for n-dimensional operations inside this real field
  */
 @UnstableKMathAPI
-public inline fun <R> DoubleField.withNdAlgebra(vararg shape: Int, action: DoubleFieldND.() -> R): R {
+public inline fun <R> Float64Field.withNdAlgebra(vararg shape: Int, action: Float64FieldND.() -> R): R {
     contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
-    return DoubleFieldND(ShapeND(shape)).run(action)
+    return Float64FieldND(ShapeND(shape)).run(action)
 }
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Int16RingND.kt
similarity index 51%
rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt
rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Int16RingND.kt
index 1b4647146..d76120c59 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Int16RingND.kt
@@ -1,34 +1,33 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.nd
 
 import space.kscience.kmath.UnstableKMathAPI
+import space.kscience.kmath.operations.Int16Ring
 import space.kscience.kmath.operations.NumbersAddOps
-import space.kscience.kmath.operations.ShortRing
 import space.kscience.kmath.operations.bufferAlgebra
 import kotlin.contracts.InvocationKind
 import kotlin.contracts.contract
 
-public sealed class ShortRingOpsND : BufferedRingOpsND<Short, ShortRing>(ShortRing.bufferAlgebra) {
-    public companion object : ShortRingOpsND()
+public sealed class Int16RingOpsND : BufferedRingOpsND<Short, Int16Ring>(Int16Ring.bufferAlgebra) {
+    public companion object : Int16RingOpsND()
 }
 
 @OptIn(UnstableKMathAPI::class)
-public class ShortRingND(
-    override val shape: ShapeND
-) : ShortRingOpsND(), RingND<Short, ShortRing>, NumbersAddOps<StructureND<Short>> {
+public class Int16RingND(
+    override val shape: ShapeND,
+) : Int16RingOpsND(), RingND<Short, Int16Ring>, NumbersAddOps<StructureND<Short>> {
 
     override fun number(value: Number): BufferND<Short> {
-        val short
-        = value.toShort() // minimize conversions
+        val short = value.toShort() // minimize conversions
         return structureND(shape) { short }
     }
 }
 
-public inline fun <R> ShortRing.withNdAlgebra(vararg shape: Int, action: ShortRingND.() -> R): R {
+public inline fun <R> Int16Ring.withNdAlgebra(vararg shape: Int, action: Int16RingND.() -> R): R {
     contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
-    return ShortRingND(ShapeND(shape)).run(action)
+    return Int16RingND(ShapeND(shape)).run(action)
 }
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/IntRingND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/IntRingND.kt
index 1491950d6..dfcf39965 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/IntRingND.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/IntRingND.kt
@@ -1,30 +1,30 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.nd
 
 import space.kscience.kmath.UnstableKMathAPI
-import space.kscience.kmath.operations.IntRing
+import space.kscience.kmath.operations.Int32Ring
 import space.kscience.kmath.operations.NumbersAddOps
 import space.kscience.kmath.operations.bufferAlgebra
-import space.kscience.kmath.structures.IntBuffer
+import space.kscience.kmath.structures.Int32Buffer
 import kotlin.contracts.InvocationKind
 import kotlin.contracts.contract
 
 public class IntBufferND(
     indexes: ShapeIndexer,
-    override val buffer: IntBuffer,
+    override val buffer: Int32Buffer,
 ) : MutableBufferND<Int>(indexes, buffer)
 
-public sealed class IntRingOpsND : BufferedRingOpsND<Int, IntRing>(IntRing.bufferAlgebra) {
+public sealed class IntRingOpsND : BufferedRingOpsND<Int, Int32Ring>(Int32Ring.bufferAlgebra) {
 
-    override fun structureND(shape: ShapeND, initializer: IntRing.(IntArray) -> Int): IntBufferND {
+    override fun structureND(shape: ShapeND, initializer: Int32Ring.(IntArray) -> Int): IntBufferND {
         val indexer = indexerBuilder(shape)
         return IntBufferND(
             indexer,
-            IntBuffer(indexer.linearSize) { offset ->
+            Int32Buffer(indexer.linearSize) { offset ->
                 elementAlgebra.initializer(indexer.index(offset))
             }
         )
@@ -35,8 +35,8 @@ public sealed class IntRingOpsND : BufferedRingOpsND<Int, IntRing>(IntRing.buffe
 
 @OptIn(UnstableKMathAPI::class)
 public class IntRingND(
-    override val shape: ShapeND
-) : IntRingOpsND(), RingND<Int, IntRing>, NumbersAddOps<StructureND<Int>> {
+    override val shape: ShapeND,
+) : IntRingOpsND(), RingND<Int, Int32Ring>, NumbersAddOps<StructureND<Int>> {
 
     override fun number(value: Number): BufferND<Int> {
         val int = value.toInt() // minimize conversions
@@ -44,7 +44,7 @@ public class IntRingND(
     }
 }
 
-public inline fun <R> IntRing.withNdAlgebra(vararg shape: Int, action: IntRingND.() -> R): R {
+public inline fun <R> Int32Ring.withNdAlgebra(vararg shape: Int, action: IntRingND.() -> R): R {
     contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
     return IntRingND(ShapeND(shape)).run(action)
 }
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/PermutedStructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/PermutedStructureND.kt
index 6c35e2f44..28130c037 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/PermutedStructureND.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/PermutedStructureND.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -32,7 +32,6 @@ public class PermutedMutableStructureND<T>(
     public val permutation: (IntArray) -> IntArray,
 ) : MutableStructureND<T> {
 
-
     @OptIn(PerformancePitfall::class)
     override fun set(index: IntArray, value: T) {
         origin[permutation(index)] = value
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndices.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndices.kt
index 3a27614c5..e8545125f 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndices.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndices.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeND.kt
index d43ebaf1c..d5cdc6286 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeND.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeND.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -68,6 +68,9 @@ public operator fun ShapeND.component3(): Int = get(2)
  */
 public fun ShapeND.toArray(): IntArray = array.copyOf()
 
+/**
+ * Provide internal content of [ShapeND]. Must not be modified.
+ */
 @UnsafeKMathAPI
 public fun ShapeND.asArray(): IntArray = array
 
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt
index 984b5ad0f..14f2aa7c2 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -9,7 +9,6 @@ import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.operations.asSequence
 import space.kscience.kmath.structures.Buffer
 import space.kscience.kmath.structures.MutableBuffer
-import space.kscience.kmath.structures.asMutableBuffer
 import kotlin.jvm.JvmInline
 
 /**
@@ -46,6 +45,7 @@ public interface MutableStructure1D<T> : Structure1D<T>, MutableStructureND<T>,
  */
 @JvmInline
 private value class Structure1DWrapper<out T>(val structure: StructureND<T>) : Structure1D<T> {
+
     override val shape: ShapeND get() = structure.shape
     override val size: Int get() = structure.shape[0]
 
@@ -60,6 +60,7 @@ private value class Structure1DWrapper<out T>(val structure: StructureND<T>) : S
  * A 1D wrapper for a mutable nd-structure
  */
 private class MutableStructure1DWrapper<T>(val structure: MutableStructureND<T>) : MutableStructure1D<T> {
+
     override val shape: ShapeND get() = structure.shape
     override val size: Int get() = structure.shape[0]
 
@@ -74,13 +75,6 @@ private class MutableStructure1DWrapper<T>(val structure: MutableStructureND<T>)
         structure[intArrayOf(index)] = value
     }
 
-    @OptIn(PerformancePitfall::class)
-    override fun copy(): MutableBuffer<T> = structure
-        .elements()
-        .map(Pair<IntArray, T>::second)
-        .toMutableList()
-        .asMutableBuffer()
-
     override fun toString(): String = Buffer.toString(this)
 }
 
@@ -90,6 +84,7 @@ private class MutableStructure1DWrapper<T>(val structure: MutableStructureND<T>)
  */
 @JvmInline
 private value class Buffer1DWrapper<out T>(val buffer: Buffer<T>) : Structure1D<T> {
+
     override val shape: ShapeND get() = ShapeND(buffer.size)
     override val size: Int get() = buffer.size
 
@@ -102,6 +97,7 @@ private value class Buffer1DWrapper<out T>(val buffer: Buffer<T>) : Structure1D<
 }
 
 internal class MutableBuffer1DWrapper<T>(val buffer: MutableBuffer<T>) : MutableStructure1D<T> {
+
     override val shape: ShapeND get() = ShapeND(buffer.size)
     override val size: Int get() = buffer.size
 
@@ -115,8 +111,6 @@ internal class MutableBuffer1DWrapper<T>(val buffer: MutableBuffer<T>) : Mutable
         buffer[index] = value
     }
 
-    override fun copy(): MutableBuffer<T> = buffer.copy()
-
     override fun toString(): String = Buffer.toString(this)
 }
 
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt
index e006d09eb..0a3209970 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt
@@ -1,17 +1,16 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.nd
 
+import space.kscience.attributes.Attributes
 import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.structures.Buffer
 import space.kscience.kmath.structures.MutableBuffer
-import space.kscience.kmath.structures.MutableListBuffer
 import space.kscience.kmath.structures.VirtualBuffer
 import kotlin.jvm.JvmInline
-import kotlin.reflect.KClass
 
 /**
  * A structure that is guaranteed to be two-dimensional.
@@ -32,14 +31,14 @@ public interface Structure2D<out T> : StructureND<T> {
     override val shape: ShapeND get() = ShapeND(rowNum, colNum)
 
     /**
-     * The buffer of rows of this structure. It gets elements from the structure dynamically.
+     * The buffer of rows for this structure. It gets elements from the structure dynamically.
      */
     @PerformancePitfall
     public val rows: List<Buffer<T>>
         get() = List(rowNum) { i -> VirtualBuffer(colNum) { j -> get(i, j) } }
 
     /**
-     * The buffer of columns of this structure. It gets elements from the structure dynamically.
+     * The buffer of columns for this structure. It gets elements from the structure dynamically.
      */
     @PerformancePitfall
     public val columns: List<Buffer<T>>
@@ -69,6 +68,25 @@ public interface Structure2D<out T> : StructureND<T> {
     public companion object
 }
 
+/**
+ * A linear accessor for a [MutableStructureND]
+ */
+@OptIn(PerformancePitfall::class)
+public class MutableStructureNDAccessorBuffer<T>(
+    public val structure: MutableStructureND<T>,
+    override val size: Int,
+    private val indexer: (Int) -> IntArray,
+) : MutableBuffer<T> {
+
+    override fun set(index: Int, value: T) {
+        structure[indexer(index)] = value
+    }
+
+    override fun get(index: Int): T = structure[indexer(index)]
+
+    override fun toString(): String = "AccessorBuffer(structure=$structure, size=$size)"
+}
+
 /**
  * Represents mutable [Structure2D].
  */
@@ -87,14 +105,18 @@ public interface MutableStructure2D<T> : Structure2D<T>, MutableStructureND<T> {
      */
     @PerformancePitfall
     override val rows: List<MutableBuffer<T>>
-        get() = List(rowNum) { i -> MutableListBuffer(colNum) { j -> get(i, j) } }
+        get() = List(rowNum) { i ->
+            MutableStructureNDAccessorBuffer(this, colNum) { j -> intArrayOf(i, j) }
+        }
 
     /**
-     * The buffer of columns of this structure. It gets elements from the structure dynamically.
+     * The buffer of columns for this structure. It gets elements from the structure dynamically.
      */
     @PerformancePitfall
     override val columns: List<MutableBuffer<T>>
-        get() = List(colNum) { j -> MutableListBuffer(rowNum) { i -> get(i, j) } }
+        get() = List(colNum) { j ->
+            MutableStructureNDAccessorBuffer(this, rowNum) { i -> intArrayOf(i, j) }
+        }
 }
 
 /**
@@ -102,6 +124,7 @@ public interface MutableStructure2D<T> : Structure2D<T>, MutableStructureND<T> {
  */
 @JvmInline
 private value class Structure2DWrapper<out T>(val structure: StructureND<T>) : Structure2D<T> {
+
     override val shape: ShapeND get() = structure.shape
 
     override val rowNum: Int get() = shape[0]
@@ -110,7 +133,8 @@ private value class Structure2DWrapper<out T>(val structure: StructureND<T>) : S
     @PerformancePitfall
     override operator fun get(i: Int, j: Int): T = structure[i, j]
 
-    override fun <F : StructureFeature> getFeature(type: KClass<out F>): F? = structure.getFeature(type)
+    override val attributes: Attributes
+        get() = structure.attributes
 
     @PerformancePitfall
     override fun elements(): Sequence<Pair<IntArray, T>> = structure.elements()
@@ -120,6 +144,7 @@ private value class Structure2DWrapper<out T>(val structure: StructureND<T>) : S
  * A 2D wrapper for a mutable nd-structure
  */
 private class MutableStructure2DWrapper<T>(val structure: MutableStructureND<T>) : MutableStructure2D<T> {
+
     override val shape: ShapeND get() = structure.shape
 
     override val rowNum: Int get() = shape[0]
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt
index e643186ba..5c1021147 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt
@@ -1,23 +1,22 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.nd
 
+import space.kscience.attributes.Attribute
+import space.kscience.attributes.AttributeContainer
+import space.kscience.attributes.Attributes
+import space.kscience.attributes.SafeType
 import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.linear.LinearSpace
-import space.kscience.kmath.misc.Feature
-import space.kscience.kmath.misc.Featured
 import space.kscience.kmath.operations.Ring
 import space.kscience.kmath.operations.invoke
 import space.kscience.kmath.structures.Buffer
-import space.kscience.kmath.structures.BufferFactory
-import kotlin.jvm.JvmName
 import kotlin.math.abs
-import kotlin.reflect.KClass
 
-public interface StructureFeature : Feature<StructureFeature>
+public interface StructureAttribute<T> : Attribute<T>
 
 /**
  * Represents n-dimensional structure i.e., multidimensional container of items of the same type and size. The number
@@ -28,9 +27,9 @@ public interface StructureFeature : Feature<StructureFeature>
  *
  * @param T the type of items.
  */
-public interface StructureND<out T> : Featured<StructureFeature>, WithShape {
+public interface StructureND<out T> : AttributeContainer, WithShape {
     /**
-     * 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 for
      * this structure.
      */
     override val shape: ShapeND
@@ -57,11 +56,7 @@ public interface StructureND<out T> : Featured<StructureFeature>, WithShape {
     @PerformancePitfall
     public fun elements(): Sequence<Pair<IntArray, T>> = indices.asSequence().map { it to get(it) }
 
-    /**
-     * Feature is some additional structure information that allows to access it special properties or hints.
-     * If the feature is not present, `null` is returned.
-     */
-    override fun <F : StructureFeature> getFeature(type: KClass<out F>): F? = null
+    override val attributes: Attributes get() = Attributes.EMPTY
 
     public companion object {
         /**
@@ -121,57 +116,53 @@ public interface StructureND<out T> : Featured<StructureFeature>, WithShape {
             return "$className(shape=${structure.shape}, buffer=$bufferRepr)"
         }
 
-        /**
-         * Creates a NDStructure with explicit buffer factory.
-         *
-         * Strides should be reused if possible.
-         */
-        public fun <T> buffered(
-            strides: Strides,
-            bufferFactory: BufferFactory<T> = BufferFactory.boxing(),
-            initializer: (IntArray) -> T,
-        ): BufferND<T> = BufferND(strides, bufferFactory(strides.linearSize) { i -> initializer(strides.index(i)) })
-
-        /**
-         * Inline create NDStructure with non-boxing buffer implementation if it is possible
-         */
-        public inline fun <reified T : Any> auto(
-            strides: Strides,
-            crossinline initializer: (IntArray) -> T,
-        ): BufferND<T> = BufferND(strides, Buffer.auto(strides.linearSize) { i -> initializer(strides.index(i)) })
-
-        public inline fun <T : Any> auto(
-            type: KClass<T>,
-            strides: Strides,
-            crossinline initializer: (IntArray) -> T,
-        ): BufferND<T> = BufferND(strides, Buffer.auto(type, strides.linearSize) { i -> initializer(strides.index(i)) })
-
-        public fun <T> buffered(
-            shape: ShapeND,
-            bufferFactory: BufferFactory<T> = BufferFactory.boxing(),
-            initializer: (IntArray) -> T,
-        ): BufferND<T> = buffered(ColumnStrides(shape), bufferFactory, initializer)
-
-        public inline fun <reified T : Any> auto(
-            shape: ShapeND,
-            crossinline initializer: (IntArray) -> T,
-        ): BufferND<T> = auto(ColumnStrides(shape), initializer)
-
-        @JvmName("autoVarArg")
-        public inline fun <reified T : Any> auto(
-            vararg shape: Int,
-            crossinline initializer: (IntArray) -> T,
-        ): BufferND<T> =
-            auto(ColumnStrides(ShapeND(shape)), initializer)
-
-        public inline fun <T : Any> auto(
-            type: KClass<T>,
-            vararg shape: Int,
-            crossinline initializer: (IntArray) -> T,
-        ): BufferND<T> = auto(type, ColumnStrides(ShapeND(shape)), initializer)
     }
 }
 
+
+/**
+ * Creates a NDStructure with explicit buffer factory.
+ *
+ * Strides should be reused if possible.
+ */
+public fun <T> BufferND(
+    type: SafeType<T>,
+    strides: Strides,
+    initializer: (IntArray) -> T,
+): BufferND<T> = BufferND(strides, Buffer(type, strides.linearSize) { i -> initializer(strides.index(i)) })
+
+
+public fun <T> BufferND(
+    type: SafeType<T>,
+    shape: ShapeND,
+    initializer: (IntArray) -> T,
+): BufferND<T> = BufferND(type, ColumnStrides(shape), initializer)
+
+/**
+ * Inline create NDStructure with non-boxing buffer implementation if it is possible
+ */
+public inline fun <reified T : Any> BufferND(
+    strides: Strides,
+    crossinline initializer: (IntArray) -> T,
+): BufferND<T> = BufferND(strides, Buffer(strides.linearSize) { i -> initializer(strides.index(i)) })
+
+public inline fun <reified T : Any> BufferND(
+    shape: ShapeND,
+    crossinline initializer: (IntArray) -> T,
+): BufferND<T> = BufferND(ColumnStrides(shape), initializer)
+
+public inline fun <reified T : Any> BufferND(
+    vararg shape: Int,
+    crossinline initializer: (IntArray) -> T,
+): BufferND<T> = BufferND(ColumnStrides(ShapeND(shape)), initializer)
+
+public fun <T : Any> BufferND(
+    type: SafeType<T>,
+    vararg shape: Int,
+    initializer: (IntArray) -> T,
+): BufferND<T> = BufferND(type, ColumnStrides(ShapeND(shape)), initializer)
+
+
 /**
  * Indicates whether some [StructureND] is equal to another one.
  */
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt
index 606b9a631..a7e0b0053 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt
index f0d4bd7f5..7bd5f8350 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -14,9 +14,15 @@ import kotlin.jvm.JvmName
 public fun <T, A : Algebra<T>> AlgebraND<T, A>.structureND(
     shapeFirst: Int,
     vararg shapeRest: Int,
-    initializer: A.(IntArray) -> T
+    initializer: A.(IntArray) -> T,
 ): StructureND<T> = structureND(ShapeND(shapeFirst, *shapeRest), initializer)
 
+public fun <T, A : Algebra<T>> AlgebraND<T, A>.mutableStructureND(
+    shapeFirst: Int,
+    vararg shapeRest: Int,
+    initializer: A.(IntArray) -> T,
+): MutableStructureND<T> = mutableStructureND(ShapeND(shapeFirst, *shapeRest), initializer)
+
 public fun <T, A : Group<T>> AlgebraND<T, A>.zero(shape: ShapeND): StructureND<T> = structureND(shape) { zero }
 
 @JvmName("zeroVarArg")
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/operationsND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/operationsND.kt
index 40db5187f..b91f2bde5 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/operationsND.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/operationsND.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/primitiveStructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/primitiveStructureND.kt
index 28e32363f..4831b4138 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/primitiveStructureND.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/primitiveStructureND.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,6 +8,7 @@ package space.kscience.kmath.nd
 import space.kscience.kmath.PerformancePitfall
 
 public interface StructureNDOfDouble : StructureND<Double> {
+
     /**
      * Guaranteed non-blocking access to content
      */
@@ -22,6 +23,7 @@ public fun StructureND<Double>.getDouble(index: IntArray): Double =
     if (this is StructureNDOfDouble) getDouble(index) else get(index)
 
 public interface MutableStructureNDOfDouble : StructureNDOfDouble, MutableStructureND<Double> {
+
     /**
      * Guaranteed non-blocking access to content
      */
@@ -34,6 +36,7 @@ public fun MutableStructureND<Double>.getDouble(index: IntArray): Double =
 
 
 public interface StructureNDOfInt : StructureND<Int> {
+
     /**
      * Guaranteed non-blocking access to content
      */
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt
index 0960ab023..2f21e47d6 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt
@@ -1,10 +1,12 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.operations
 
+import space.kscience.attributes.SafeType
+import space.kscience.attributes.WithType
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.expressions.Symbol
 import space.kscience.kmath.operations.Ring.Companion.optimizedPower
@@ -13,14 +15,15 @@ import space.kscience.kmath.structures.MutableBufferFactory
 /**
  * Represents an algebraic structure.
  *
- * @param T the type of element of this structure.
+ * @param T the type of element which Algebra operates on.
  */
-public interface Algebra<T> {
-
+public interface Algebra<T> : WithType<T> {
     /**
      * Provide a factory for buffers, associated with this [Algebra]
      */
-    public val bufferFactory: MutableBufferFactory<T> get() = MutableBufferFactory.boxing()
+    public val bufferFactory: MutableBufferFactory<T>
+
+    override val type: SafeType<T> get() = bufferFactory.type
 
     /**
      * Wraps a raw string to [T] object. This method is designed for three purposes:
@@ -67,12 +70,12 @@ public interface Algebra<T> {
      *
      * @param operation the name of operation.
      * @param arg the argument of operation.
-     * @return a result of operation.
+     * @return the result of the operation.
      */
     public fun unaryOperation(operation: String, arg: T): T = unaryOperationFunction(operation)(arg)
 
     /**
-     * Dynamically dispatches a binary operation with the certain name.
+     * Dynamically dispatches a binary operation with a certain name.
      *
      * Implementations must fulfil the following requirements:
      *
@@ -87,7 +90,7 @@ public interface Algebra<T> {
         error("Binary operation '$operation' not defined in $this")
 
     /**
-     * Dynamically invokes a binary operation with the certain name.
+     * Dynamically invokes a binary operation with a certain name.
      *
      * Implementations must fulfil the following requirements:
      *
@@ -265,7 +268,7 @@ public interface Ring<T> : Group<T>, RingOps<T> {
      */
     public fun power(arg: T, pow: UInt): T = optimizedPower(arg, pow)
 
-    public companion object{
+    public companion object {
         /**
          * Raises [arg] to the non-negative integer power [exponent].
          *
@@ -300,7 +303,7 @@ public interface Ring<T> : Group<T>, RingOps<T> {
  * 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 the semifield element.
  */
 public interface FieldOps<T> : RingOps<T> {
     /**
@@ -336,17 +339,19 @@ public interface FieldOps<T> : RingOps<T> {
 
 /**
  * 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.**
  *
- * @param T the type of element of this field.
+ * @param T the type of the field element.
  */
 public interface Field<T> : Ring<T>, FieldOps<T>, ScaleOperations<T>, NumericAlgebra<T> {
     override fun number(value: Number): T = scale(one, value.toDouble())
 
     public fun power(arg: T, pow: Int): T = optimizedPower(arg, pow)
 
-    public companion object{
+    public companion object {
         /**
          * Raises [arg] to the integer power [exponent].
          *
@@ -359,7 +364,11 @@ public interface Field<T> : Ring<T>, FieldOps<T>, ScaleOperations<T>, NumericAlg
          * @author Iaroslav Postovalov, Evgeniy Zhelenskiy
          */
         private fun <T> Field<T>.optimizedPower(arg: T, exponent: Int): T = when {
-            exponent < 0 -> one / (this as Ring<T>).optimizedPower(arg, if (exponent == Int.MIN_VALUE) Int.MAX_VALUE.toUInt().inc() else (-exponent).toUInt())
+            exponent < 0 -> one / (this as Ring<T>).optimizedPower(
+                arg,
+                if (exponent == Int.MIN_VALUE) Int.MAX_VALUE.toUInt().inc() else (-exponent).toUInt()
+            )
+
             else -> (this as Ring<T>).optimizedPower(arg, exponent.toUInt())
         }
     }
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt
index 34a6d4a80..c10237324 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -10,13 +10,13 @@ import space.kscience.kmath.nd.BufferedRingOpsND
 import space.kscience.kmath.operations.BigInt.Companion.BASE
 import space.kscience.kmath.operations.BigInt.Companion.BASE_SIZE
 import space.kscience.kmath.structures.Buffer
+import space.kscience.kmath.structures.MutableBufferFactory
 import kotlin.math.log2
 import kotlin.math.max
 import kotlin.math.min
 import kotlin.math.sign
 
 private typealias Magnitude = UIntArray
-private typealias TBase = ULong
 
 /**
  * Kotlin Multiplatform implementation of Big Integer numbers (KBigInteger).
@@ -26,6 +26,9 @@ private typealias TBase = ULong
  */
 @OptIn(UnstableKMathAPI::class)
 public object BigIntField : Field<BigInt>, NumbersAddOps<BigInt>, ScaleOperations<BigInt> {
+
+    override val bufferFactory: MutableBufferFactory<BigInt> = MutableBufferFactory()
+
     override val zero: BigInt = BigInt.ZERO
     override val one: BigInt = BigInt.ONE
 
@@ -451,10 +454,12 @@ public fun String.parseBigInteger(): BigInt? {
             sign = +1
             1
         }
+
         '-' -> {
             sign = -1
             1
         }
+
         else -> {
             sign = +1
             0
@@ -528,10 +533,10 @@ public fun String.parseBigInteger(): BigInt? {
 public val BigInt.algebra: BigIntField get() = BigIntField
 
 public inline fun BigInt.Companion.buffer(size: Int, initializer: (Int) -> BigInt): Buffer<BigInt> =
-    Buffer.boxing(size, initializer)
+    Buffer(size, initializer)
 
 public inline fun BigInt.Companion.mutableBuffer(size: Int, initializer: (Int) -> BigInt): Buffer<BigInt> =
-    Buffer.boxing(size, initializer)
+    Buffer(size, initializer)
 
 public val BigIntField.nd: BufferedRingOpsND<BigInt, BigIntField>
     get() = BufferedRingOpsND(BufferRingOps(BigIntField))
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt
index af0bc4d9b..6c260db9f 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt
@@ -1,12 +1,13 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.operations
 
 import space.kscience.kmath.structures.Buffer
-import space.kscience.kmath.structures.BufferFactory
+import space.kscience.kmath.structures.MutableBuffer
+import space.kscience.kmath.structures.MutableBufferFactory
 
 public interface WithSize {
     public val size: Int
@@ -17,7 +18,10 @@ public interface WithSize {
  */
 public interface BufferAlgebra<T, out A : Algebra<T>> : Algebra<Buffer<T>> {
     public val elementAlgebra: A
-    public val elementBufferFactory: BufferFactory<T> get() = elementAlgebra.bufferFactory
+
+    public val elementBufferFactory: MutableBufferFactory<T> get() = elementAlgebra.bufferFactory
+
+    override val bufferFactory: MutableBufferFactory<Buffer<T>> get() = MutableBufferFactory()
 
     public fun buffer(size: Int, vararg elements: T): Buffer<T> {
         require(elements.size == size) { "Expected $size elements but found ${elements.size}" }
@@ -73,13 +77,11 @@ private inline fun <T, A : Algebra<T>> BufferAlgebra<T, A>.zipInline(
     return elementBufferFactory(l.size) { elementAlgebra.block(l[it], r[it]) }
 }
 
-public fun <T> BufferAlgebra<T, *>.buffer(size: Int, initializer: (Int) -> T): Buffer<T> {
-    return elementBufferFactory(size, initializer)
-}
+public fun <T> BufferAlgebra<T, *>.buffer(size: Int, initializer: (Int) -> T): MutableBuffer<T> =
+    elementBufferFactory(size, initializer)
 
-public fun <T, A> A.buffer(initializer: (Int) -> T): Buffer<T> where A : BufferAlgebra<T, *>, A : WithSize {
-    return elementBufferFactory(size, initializer)
-}
+public fun <T, A> A.buffer(initializer: (Int) -> T): MutableBuffer<T> where A : BufferAlgebra<T, *>, A : WithSize =
+    elementBufferFactory(size, initializer)
 
 public fun <T, A : TrigonometricOperations<T>> BufferAlgebra<T, A>.sin(arg: Buffer<T>): Buffer<T> =
     mapInline(arg) { sin(it) }
@@ -142,11 +144,11 @@ public open class BufferRingOps<T, A : Ring<T>>(
         super<BufferAlgebra>.binaryOperationFunction(operation)
 }
 
-public val IntRing.bufferAlgebra: BufferRingOps<Int, IntRing>
-    get() = BufferRingOps(IntRing)
+public val Int32Ring.bufferAlgebra: BufferRingOps<Int, Int32Ring>
+    get() = BufferRingOps(Int32Ring)
 
-public val ShortRing.bufferAlgebra: BufferRingOps<Short, ShortRing>
-    get() = BufferRingOps(ShortRing)
+public val Int16Ring.bufferAlgebra: BufferRingOps<Short, Int16Ring>
+    get() = BufferRingOps(Int16Ring)
 
 public open class BufferFieldOps<T, A : Field<T>>(
     elementAlgebra: A,
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt
deleted file mode 100644
index 2e6b63a92..000000000
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2018-2022 KMath contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package space.kscience.kmath.operations
-
-import space.kscience.kmath.structures.Buffer
-import space.kscience.kmath.structures.DoubleBuffer
-
-/**
- * [ExtendedField] over [DoubleBuffer].
- *
- * @property size the size of buffers to operate on.
- */
-public class DoubleBufferField(public val size: Int) : ExtendedField<Buffer<Double>>, DoubleBufferOps() {
-    override val zero: Buffer<Double> by lazy { DoubleBuffer(size) { 0.0 } }
-    override val one: Buffer<Double> by lazy { DoubleBuffer(size) { 1.0 } }
-
-    override fun sinh(arg: Buffer<Double>): DoubleBuffer = super<DoubleBufferOps>.sinh(arg)
-
-    override fun cosh(arg: Buffer<Double>): DoubleBuffer = super<DoubleBufferOps>.cosh(arg)
-
-    override fun tanh(arg: Buffer<Double>): DoubleBuffer = super<DoubleBufferOps>.tanh(arg)
-
-    override fun asinh(arg: Buffer<Double>): DoubleBuffer = super<DoubleBufferOps>.asinh(arg)
-
-    override fun acosh(arg: Buffer<Double>): DoubleBuffer = super<DoubleBufferOps>.acosh(arg)
-
-    override fun atanh(arg: Buffer<Double>): DoubleBuffer = super<DoubleBufferOps>.atanh(arg)
-
-    override fun power(arg: Buffer<Double>, pow: Number): DoubleBuffer = if (pow.isInteger()) {
-        arg.map { it.pow(pow.toInt()) }
-    } else {
-        arg.map {
-            if(it<0) throw IllegalArgumentException("Negative argument $it could not be raised to the fractional power")
-            it.pow(pow.toDouble())
-        }
-    }
-
-    override fun unaryOperationFunction(operation: String): (arg: Buffer<Double>) -> Buffer<Double> =
-        super<ExtendedField>.unaryOperationFunction(operation)
-}
\ No newline at end of file
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Float64BufferField.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Float64BufferField.kt
new file mode 100644
index 000000000..1c4bda18f
--- /dev/null
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Float64BufferField.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.operations
+
+import space.kscience.kmath.structures.Buffer
+import space.kscience.kmath.structures.Float64Buffer
+
+/**
+ * [ExtendedField] over [Float64Buffer].
+ *
+ * @property size the size of buffers to operate on.
+ */
+public class Float64BufferField(public val size: Int) : ExtendedField<Buffer<Double>>, Float64BufferOps() {
+    override val zero: Buffer<Double> by lazy { Float64Buffer(size) { 0.0 } }
+    override val one: Buffer<Double> by lazy { Float64Buffer(size) { 1.0 } }
+
+    override fun sinh(arg: Buffer<Double>): Float64Buffer = super<Float64BufferOps>.sinh(arg)
+
+    override fun cosh(arg: Buffer<Double>): Float64Buffer = super<Float64BufferOps>.cosh(arg)
+
+    override fun tanh(arg: Buffer<Double>): Float64Buffer = super<Float64BufferOps>.tanh(arg)
+
+    override fun asinh(arg: Buffer<Double>): Float64Buffer = super<Float64BufferOps>.asinh(arg)
+
+    override fun acosh(arg: Buffer<Double>): Float64Buffer = super<Float64BufferOps>.acosh(arg)
+
+    override fun atanh(arg: Buffer<Double>): Float64Buffer = super<Float64BufferOps>.atanh(arg)
+
+    override fun power(arg: Buffer<Double>, pow: Number): Float64Buffer = if (pow.isInteger()) {
+        arg.map { it.pow(pow.toInt()) }
+    } else {
+        arg.map {
+            if (it < 0) throw IllegalArgumentException("Negative argument $it could not be raised to the fractional power")
+            it.pow(pow.toDouble())
+        }
+    }
+
+    override fun unaryOperationFunction(operation: String): (arg: Buffer<Double>) -> Buffer<Double> =
+        super<ExtendedField>.unaryOperationFunction(operation)
+}
\ No newline at end of file
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Float64BufferOps.kt
similarity index 50%
rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt
rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Float64BufferOps.kt
index 74b41be9d..ca4eacb8a 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Float64BufferOps.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -12,34 +12,34 @@ import kotlin.math.pow
 import kotlin.math.sqrt
 
 /**
- * [ExtendedFieldOps] over [DoubleBuffer].
+ * [ExtendedFieldOps] over [Float64Buffer].
  */
-public abstract class DoubleBufferOps : BufferAlgebra<Double, DoubleField>, ExtendedFieldOps<Buffer<Double>>,
+public abstract class Float64BufferOps : BufferAlgebra<Double, Float64Field>, ExtendedFieldOps<Buffer<Double>>,
     Norm<Buffer<Double>, Double> {
 
-    override val elementAlgebra: DoubleField get() = DoubleField
+    override val elementAlgebra: Float64Field get() = Float64Field
 
     override val elementBufferFactory: MutableBufferFactory<Double> get() = elementAlgebra.bufferFactory
 
     @Suppress("OVERRIDE_BY_INLINE")
     @OptIn(UnstableKMathAPI::class)
-    final override inline fun Buffer<Double>.map(block: DoubleField.(Double) -> Double): DoubleBuffer =
-        DoubleArray(size) { DoubleField.block(getDouble(it)) }.asBuffer()
+    final override inline fun Buffer<Double>.map(block: Float64Field.(Double) -> Double): Float64Buffer =
+        DoubleArray(size) { Float64Field.block(getDouble(it)) }.asBuffer()
 
 
     @OptIn(UnstableKMathAPI::class)
     @Suppress("OVERRIDE_BY_INLINE")
-    final override inline fun Buffer<Double>.mapIndexed(block: DoubleField.(index: Int, arg: Double) -> Double): DoubleBuffer =
-        DoubleBuffer(size) { DoubleField.block(it, getDouble(it)) }
+    final override inline fun Buffer<Double>.mapIndexed(block: Float64Field.(index: Int, arg: Double) -> Double): Float64Buffer =
+        Float64Buffer(size) { Float64Field.block(it, getDouble(it)) }
 
     @OptIn(UnstableKMathAPI::class)
     @Suppress("OVERRIDE_BY_INLINE")
     final override inline fun Buffer<Double>.zip(
         other: Buffer<Double>,
-        block: DoubleField.(left: Double, right: Double) -> Double,
-    ): DoubleBuffer {
+        block: Float64Field.(left: Double, right: Double) -> Double,
+    ): Float64Buffer {
         require(size == other.size) { "Incompatible buffer sizes. left: ${size}, right: ${other.size}" }
-        return DoubleBuffer(size) { DoubleField.block(getDouble(it), other.getDouble(it)) }
+        return Float64Buffer(size) { Float64Field.block(getDouble(it), other.getDouble(it)) }
     }
 
     override fun unaryOperationFunction(operation: String): (arg: Buffer<Double>) -> Buffer<Double> =
@@ -48,32 +48,32 @@ public abstract class DoubleBufferOps : BufferAlgebra<Double, DoubleField>, Exte
     override fun binaryOperationFunction(operation: String): (left: Buffer<Double>, right: Buffer<Double>) -> Buffer<Double> =
         super<ExtendedFieldOps>.binaryOperationFunction(operation)
 
-    override fun Buffer<Double>.unaryMinus(): DoubleBuffer = map { -it }
+    override fun Buffer<Double>.unaryMinus(): Float64Buffer = map { -it }
 
-    override fun add(left: Buffer<Double>, right: Buffer<Double>): DoubleBuffer {
+    override fun add(left: Buffer<Double>, right: Buffer<Double>): Float64Buffer {
         require(right.size == left.size) {
             "The size of the first buffer ${left.size} should be the same as for second one: ${right.size} "
         }
 
-        return if (left is DoubleBuffer && right is DoubleBuffer) {
+        return if (left is Float64Buffer && right is Float64Buffer) {
             val aArray = left.array
             val bArray = right.array
-            DoubleBuffer(DoubleArray(left.size) { aArray[it] + bArray[it] })
-        } else DoubleBuffer(DoubleArray(left.size) { left[it] + right[it] })
+            Float64Buffer(DoubleArray(left.size) { aArray[it] + bArray[it] })
+        } else Float64Buffer(DoubleArray(left.size) { left[it] + right[it] })
     }
 
-    override fun Buffer<Double>.plus(arg: Buffer<Double>): DoubleBuffer = add(this, arg)
+    override fun Buffer<Double>.plus(arg: Buffer<Double>): Float64Buffer = add(this, arg)
 
-    override fun Buffer<Double>.minus(arg: Buffer<Double>): DoubleBuffer {
+    override fun Buffer<Double>.minus(arg: Buffer<Double>): Float64Buffer {
         require(arg.size == this.size) {
             "The size of the first buffer ${this.size} should be the same as for second one: ${arg.size} "
         }
 
-        return if (this is DoubleBuffer && arg is DoubleBuffer) {
+        return if (this is Float64Buffer && arg is Float64Buffer) {
             val aArray = this.array
             val bArray = arg.array
-            DoubleBuffer(DoubleArray(this.size) { aArray[it] - bArray[it] })
-        } else DoubleBuffer(DoubleArray(this.size) { this[it] - arg[it] })
+            Float64Buffer(DoubleArray(this.size) { aArray[it] - bArray[it] })
+        } else Float64Buffer(DoubleArray(this.size) { this[it] - arg[it] })
     }
 
     //
@@ -96,61 +96,61 @@ public abstract class DoubleBufferOps : BufferAlgebra<Double, DoubleField>, Exte
 //    }
 
     @UnstableKMathAPI
-    override fun multiply(left: Buffer<Double>, right: Buffer<Double>): DoubleBuffer {
+    override fun multiply(left: Buffer<Double>, right: Buffer<Double>): Float64Buffer {
         require(right.size == left.size) {
             "The size of the first buffer ${left.size} should be the same as for second one: ${right.size} "
         }
 
-        return if (left is DoubleBuffer && right is DoubleBuffer) {
+        return if (left is Float64Buffer && right is Float64Buffer) {
             val aArray = left.array
             val bArray = right.array
-            DoubleBuffer(DoubleArray(left.size) { aArray[it] * bArray[it] })
-        } else DoubleBuffer(DoubleArray(left.size) { left[it] * right[it] })
+            Float64Buffer(DoubleArray(left.size) { aArray[it] * bArray[it] })
+        } else Float64Buffer(DoubleArray(left.size) { left[it] * right[it] })
     }
 
-    override fun divide(left: Buffer<Double>, right: Buffer<Double>): DoubleBuffer {
+    override fun divide(left: Buffer<Double>, right: Buffer<Double>): Float64Buffer {
         require(right.size == left.size) {
             "The size of the first buffer ${left.size} should be the same as for second one: ${right.size} "
         }
 
-        return if (left is DoubleBuffer && right is DoubleBuffer) {
+        return if (left is Float64Buffer && right is Float64Buffer) {
             val aArray = left.array
             val bArray = right.array
-            DoubleBuffer(DoubleArray(left.size) { aArray[it] / bArray[it] })
-        } else DoubleBuffer(DoubleArray(left.size) { left[it] / right[it] })
+            Float64Buffer(DoubleArray(left.size) { aArray[it] / bArray[it] })
+        } else Float64Buffer(DoubleArray(left.size) { left[it] / right[it] })
     }
 
-    override fun sin(arg: Buffer<Double>): DoubleBuffer = arg.map { sin(it) }
+    override fun sin(arg: Buffer<Double>): Float64Buffer = arg.map { sin(it) }
 
-    override fun cos(arg: Buffer<Double>): DoubleBuffer = arg.map { cos(it) }
+    override fun cos(arg: Buffer<Double>): Float64Buffer = arg.map { cos(it) }
 
-    override fun tan(arg: Buffer<Double>): DoubleBuffer = arg.map { tan(it) }
+    override fun tan(arg: Buffer<Double>): Float64Buffer = arg.map { tan(it) }
 
-    override fun asin(arg: Buffer<Double>): DoubleBuffer = arg.map { asin(it) }
+    override fun asin(arg: Buffer<Double>): Float64Buffer = arg.map { asin(it) }
 
-    override fun acos(arg: Buffer<Double>): DoubleBuffer = arg.map { acos(it) }
+    override fun acos(arg: Buffer<Double>): Float64Buffer = arg.map { acos(it) }
 
-    override fun atan(arg: Buffer<Double>): DoubleBuffer = arg.map { atan(it) }
+    override fun atan(arg: Buffer<Double>): Float64Buffer = arg.map { atan(it) }
 
-    override fun sinh(arg: Buffer<Double>): DoubleBuffer = arg.map { sinh(it) }
+    override fun sinh(arg: Buffer<Double>): Float64Buffer = arg.map { sinh(it) }
 
-    override fun cosh(arg: Buffer<Double>): DoubleBuffer = arg.map { cosh(it) }
+    override fun cosh(arg: Buffer<Double>): Float64Buffer = arg.map { cosh(it) }
 
-    override fun tanh(arg: Buffer<Double>): DoubleBuffer = arg.map { tanh(it) }
+    override fun tanh(arg: Buffer<Double>): Float64Buffer = arg.map { tanh(it) }
 
-    override fun asinh(arg: Buffer<Double>): DoubleBuffer = arg.map { asinh(it) }
+    override fun asinh(arg: Buffer<Double>): Float64Buffer = arg.map { asinh(it) }
 
-    override fun acosh(arg: Buffer<Double>): DoubleBuffer = arg.map { acosh(it) }
+    override fun acosh(arg: Buffer<Double>): Float64Buffer = arg.map { acosh(it) }
 
-    override fun atanh(arg: Buffer<Double>): DoubleBuffer = arg.map { atanh(it) }
+    override fun atanh(arg: Buffer<Double>): Float64Buffer = arg.map { atanh(it) }
 
-    override fun exp(arg: Buffer<Double>): DoubleBuffer = arg.map { exp(it) }
+    override fun exp(arg: Buffer<Double>): Float64Buffer = arg.map { exp(it) }
 
-    override fun ln(arg: Buffer<Double>): DoubleBuffer = arg.map { ln(it) }
+    override fun ln(arg: Buffer<Double>): Float64Buffer = arg.map { ln(it) }
 
-    override fun norm(arg: Buffer<Double>): Double = DoubleL2Norm.norm(arg)
+    override fun norm(arg: Buffer<Double>): Double = Float64L2Norm.norm(arg)
 
-    override fun scale(a: Buffer<Double>, value: Double): DoubleBuffer = a.map { it * value }
+    override fun scale(a: Buffer<Double>, value: Double): Float64Buffer = a.map { it * value }
 
     override fun power(arg: Buffer<Double>, pow: Number): Buffer<Double> = if (pow is Int) {
         arg.map { it.pow(pow) }
@@ -158,37 +158,37 @@ public abstract class DoubleBufferOps : BufferAlgebra<Double, DoubleField>, Exte
         arg.map { it.pow(pow.toDouble()) }
     }
 
-    public companion object : DoubleBufferOps()
+    public companion object : Float64BufferOps()
 }
 
-public object DoubleL2Norm : Norm<Point<Double>, Double> {
+public object Float64L2Norm : Norm<Point<Double>, Double> {
     override fun norm(arg: Point<Double>): Double = sqrt(arg.fold(0.0) { acc: Double, d: Double -> acc + d.pow(2) })
 }
 
-public fun DoubleBufferOps.sum(buffer: Buffer<Double>): Double = buffer.reduce(Double::plus)
+public fun Float64BufferOps.sum(buffer: Buffer<Double>): Double = buffer.reduce(Double::plus)
 
 /**
  * Sum of elements using given [conversion]
  */
-public inline fun <T> DoubleBufferOps.sumOf(buffer: Buffer<T>, conversion: (T) -> Double): Double =
+public inline fun <T> Float64BufferOps.sumOf(buffer: Buffer<T>, conversion: (T) -> Double): Double =
     buffer.fold(0.0) { acc, value -> acc + conversion(value) }
 
-public fun DoubleBufferOps.average(buffer: Buffer<Double>): Double = sum(buffer) / buffer.size
+public fun Float64BufferOps.average(buffer: Buffer<Double>): Double = sum(buffer) / buffer.size
 
 /**
  * Average of elements using given [conversion]
  */
-public inline fun <T> DoubleBufferOps.averageOf(buffer: Buffer<T>, conversion: (T) -> Double): Double =
+public inline fun <T> Float64BufferOps.averageOf(buffer: Buffer<T>, conversion: (T) -> Double): Double =
     sumOf(buffer, conversion) / buffer.size
 
-public fun DoubleBufferOps.dispersion(buffer: Buffer<Double>): Double {
+public fun Float64BufferOps.dispersion(buffer: Buffer<Double>): Double {
     val av = average(buffer)
     return buffer.fold(0.0) { acc, value -> acc + (value - av).pow(2) } / buffer.size
 }
 
-public fun DoubleBufferOps.std(buffer: Buffer<Double>): Double = sqrt(dispersion(buffer))
+public fun Float64BufferOps.std(buffer: Buffer<Double>): Double = sqrt(dispersion(buffer))
 
-public fun DoubleBufferOps.covariance(x: Buffer<Double>, y: Buffer<Double>): Double {
+public fun Float64BufferOps.covariance(x: Buffer<Double>, y: Buffer<Double>): Double {
     require(x.size == y.size) { "Expected buffers of the same size, but x.size == ${x.size} and y.size == ${y.size}" }
     val xMean = average(x)
     val yMean = average(y)
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt
index 7aa5aed80..c4a26e242 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,7 +7,7 @@ package space.kscience.kmath.operations
 
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.expressions.Symbol
-import space.kscience.kmath.expressions.symbol
+import space.kscience.kmath.structures.MutableBufferFactory
 
 /**
  * An algebra for generic boolean logic
@@ -61,8 +61,8 @@ public interface LogicAlgebra<T : Any> : Algebra<T> {
 
 
     public companion object {
-        public val TRUE: Symbol by symbol
-        public val FALSE: Symbol by symbol
+        public val TRUE: Symbol = Symbol("TRUE")//by symbol
+        public val FALSE: Symbol = Symbol("FALSE")// by symbol
     }
 }
 
@@ -73,6 +73,8 @@ public interface LogicAlgebra<T : Any> : Algebra<T> {
 @Suppress("EXTENSION_SHADOWED_BY_MEMBER")
 public object BooleanAlgebra : LogicAlgebra<Boolean> {
 
+    override val bufferFactory: MutableBufferFactory<Boolean> get() = MutableBufferFactory()
+
     override fun const(boolean: Boolean): Boolean = boolean
 
     override fun Boolean.not(): Boolean = !this
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt
index 9bcfb00a2..4f15418b3 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -150,7 +150,7 @@ public interface ScaleOperations<T> : Algebra<T> {
  * TODO to be removed and replaced by extensions after multiple receivers are there
  */
 @UnstableKMathAPI
-public interface NumbersAddOps<T> : RingOps<T>, NumericAlgebra<T> {
+public interface NumbersAddOps<T> : GroupOps<T>, NumericAlgebra<T> {
     /**
      * Addition of element and scalar.
      *
@@ -177,7 +177,7 @@ public interface NumbersAddOps<T> : RingOps<T>, NumericAlgebra<T> {
     public operator fun T.minus(other: Number): T = this - number(other)
 
     /**
-     * Subtraction of number from element.
+     * Subtraction of number from the element.
      *
      * @receiver the minuend.
      * @param other the subtrahend.
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt
index c24394add..2aeb30be4 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -82,9 +82,9 @@ public expect fun Number.isInteger(): Boolean
 /**
  * A context extension to include power operations based on exponentiation.
  *
- * @param T the type of element of this structure.
+ * @param T the type of this structure element
  */
-public interface PowerOperations<T> : FieldOps<T> {
+public interface PowerOperations<T> : Algebra<T> {
 
     /**
      * Raises [arg] to a power if possible (negative number could not be raised to a fractional power).
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt
index ddf599240..9daccfb30 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -99,9 +99,10 @@ public fun <T> Iterable<T>.sumWith(group: Group<T>): T = group.sum(this)
  * @param group tha algebra that provides addition
  * @param extractor the (inline) lambda function to extract value
  */
-public inline fun <T, R> Iterable<T>.sumWithGroupOf(group: Group<R>, extractor: (T) -> R): R = this.fold(group.zero) { left: R, right: T ->
-    group.add(left, extractor(right))
-}
+public inline fun <T, R> Iterable<T>.sumWithGroupOf(group: Group<R>, extractor: (T) -> R): R =
+    this.fold(group.zero) { left: R, right: T ->
+        group.add(left, extractor(right))
+    }
 
 /**
  * Returns the sum of all elements in the sequence in provided space.
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/integerFields.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/integerFields.kt
new file mode 100644
index 000000000..79fb0edb7
--- /dev/null
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/integerFields.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.operations
+
+import space.kscience.kmath.operations.Int16Field.div
+import space.kscience.kmath.operations.Int32Field.div
+import space.kscience.kmath.operations.Int64Field.div
+import space.kscience.kmath.structures.Int16
+import space.kscience.kmath.structures.Int32
+import space.kscience.kmath.structures.Int64
+import space.kscience.kmath.structures.MutableBufferFactory
+import kotlin.math.roundToInt
+import kotlin.math.roundToLong
+
+
+/**
+ * A [Int16] field with integer division and scale. The division operation is done according to [Short.div] rules.
+ *
+ * Scaling is done according to [Double.roundToInt] rules.
+ *
+ * All results are converted to Int16.
+ */
+@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
+public object Int16Field : Field<Int16>, Norm<Int16, Int16>, NumericAlgebra<Int16> {
+    override val bufferFactory: MutableBufferFactory<Int16> = MutableBufferFactory<Int16>()
+    override val zero: Int16 get() = 0
+    override val one: Int16 get() = 1
+
+    override fun number(value: Number): Int16 = value.toShort()
+    override fun add(left: Int16, right: Int16): Int16 = (left + right).toShort()
+    override fun multiply(left: Int16, right: Int16): Int16 = (left * right).toShort()
+    override fun norm(arg: Int16): Int16 = abs(arg)
+
+    override fun scale(a: Int16, value: Double): Int16 = (a * value).roundToInt().toShort()
+
+    override fun divide(left: Int16, right: Int16): Int16 = (left / right).toShort()
+
+    override fun Int16.unaryMinus(): Int16 = (-this).toShort()
+}
+
+/**
+ * A [Int32] field with integer division and scale. The division operation is done according to [Int.div] rules.
+ *
+ * Scaling is done according to [Double.roundToInt] rules.
+ */
+@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
+public object Int32Field : Field<Int32>, Norm<Int32, Int32>, NumericAlgebra<Int32> {
+    override val bufferFactory: MutableBufferFactory<Int> = MutableBufferFactory()
+
+    override val zero: Int get() = 0
+    override val one: Int get() = 1
+
+    override fun number(value: Number): Int = value.toInt()
+    override fun add(left: Int, right: Int): Int = left + right
+    override fun multiply(left: Int, right: Int): Int = left * right
+    override fun norm(arg: Int): Int = abs(arg)
+
+    override fun scale(a: Int, value: Double): Int = (a * value).roundToInt()
+
+    override fun divide(left: Int, right: Int): Int = left / right
+
+    override fun Int.unaryMinus(): Int = -this
+}
+
+/**
+ * A [Int64] field with integer division and scale. The division operation is done according to [Long.div] rules.
+ *
+ * Scaling is done according to [Double.roundToLong] rules.
+ */
+@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
+public object Int64Field : Field<Int64>, Norm<Int64, Int64>, NumericAlgebra<Int64> {
+    override val bufferFactory: MutableBufferFactory<Int64> = MutableBufferFactory()
+    override val zero: Int64 get() = 0L
+    override val one: Int64 get() = 1L
+
+    override fun number(value: Number): Int64 = value.toLong()
+    override fun add(left: Int64, right: Int64): Int64 = left + right
+    override fun multiply(left: Int64, right: Int64): Int64 = left * right
+    override fun norm(arg: Int64): Int64 = abs(arg)
+
+    override fun scale(a: Int64, value: Double): Int64 = (a * value).roundToLong()
+
+    override fun divide(left: Int64, right: Int64): Int64 = left / right
+
+    override fun Int64.unaryMinus(): Int64 = -this
+}
\ No newline at end of file
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt
index 224ca1daf..96a080afd 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt
@@ -1,11 +1,10 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
-@file:Suppress("NOTHING_TO_INLINE")
 package space.kscience.kmath.operations
 
-import space.kscience.kmath.structures.*
+import space.kscience.kmath.structures.MutableBufferFactory
 import kotlin.math.pow as kpow
 
 
@@ -64,16 +63,16 @@ public interface ExtendedField<T> : ExtendedFieldOps<T>, Field<T>, NumericAlgebr
 }
 
 /**
- * A field for [Double] without boxing. Does not produce appropriate field element.
+ * A field for [Double] without boxing. Does not produce an appropriate field element.
  */
-@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE")
-public object DoubleField : ExtendedField<Double>, Norm<Double, Double>, ScaleOperations<Double> {
-    override val bufferFactory: MutableBufferFactory<Double> = MutableBufferFactory(::DoubleBuffer)
+@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
+public object Float64Field : ExtendedField<Double>, Norm<Double, Double>, ScaleOperations<Double> {
+    override val bufferFactory: MutableBufferFactory<Double> = MutableBufferFactory()
 
-    override inline val zero: Double get() = 0.0
-    override inline val one: Double get() = 1.0
+    override val zero: Double get() = 0.0
+    override val one: Double get() = 1.0
 
-    override inline fun number(value: Number): Double = value.toDouble()
+    override fun number(value: Number): Double = value.toDouble()
 
     override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double =
         when (operation) {
@@ -81,26 +80,26 @@ public object DoubleField : ExtendedField<Double>, Norm<Double, Double>, ScaleOp
             else -> super<ExtendedField>.binaryOperationFunction(operation)
         }
 
-    override inline fun add(left: Double, right: Double): Double = left + right
+    override fun add(left: Double, right: Double): Double = left + right
 
-    override inline fun multiply(left: Double, right: Double): Double = left * right
-    override inline fun divide(left: Double, right: Double): Double = left / right
+    override fun multiply(left: Double, right: Double): Double = left * right
+    override fun divide(left: Double, right: Double): Double = left / right
 
-    override inline fun scale(a: Double, value: Double): Double = a * value
+    override fun scale(a: Double, value: Double): Double = a * value
 
-    override inline fun sin(arg: Double): Double = kotlin.math.sin(arg)
-    override inline fun cos(arg: Double): Double = kotlin.math.cos(arg)
-    override inline fun tan(arg: Double): Double = kotlin.math.tan(arg)
-    override inline fun acos(arg: Double): Double = kotlin.math.acos(arg)
-    override inline fun asin(arg: Double): Double = kotlin.math.asin(arg)
-    override inline fun atan(arg: Double): Double = kotlin.math.atan(arg)
+    override fun sin(arg: Double): Double = kotlin.math.sin(arg)
+    override fun cos(arg: Double): Double = kotlin.math.cos(arg)
+    override fun tan(arg: Double): Double = kotlin.math.tan(arg)
+    override fun acos(arg: Double): Double = kotlin.math.acos(arg)
+    override fun asin(arg: Double): Double = kotlin.math.asin(arg)
+    override fun atan(arg: Double): Double = kotlin.math.atan(arg)
 
-    override inline fun sinh(arg: Double): Double = kotlin.math.sinh(arg)
-    override inline fun cosh(arg: Double): Double = kotlin.math.cosh(arg)
-    override inline fun tanh(arg: Double): Double = kotlin.math.tanh(arg)
-    override inline fun asinh(arg: Double): Double = kotlin.math.asinh(arg)
-    override inline fun acosh(arg: Double): Double = kotlin.math.acosh(arg)
-    override inline fun atanh(arg: Double): Double = kotlin.math.atanh(arg)
+    override fun sinh(arg: Double): Double = kotlin.math.sinh(arg)
+    override fun cosh(arg: Double): Double = kotlin.math.cosh(arg)
+    override fun tanh(arg: Double): Double = kotlin.math.tanh(arg)
+    override fun asinh(arg: Double): Double = kotlin.math.asinh(arg)
+    override fun acosh(arg: Double): Double = kotlin.math.acosh(arg)
+    override fun atanh(arg: Double): Double = kotlin.math.atanh(arg)
 
     override fun sqrt(arg: Double): Double = kotlin.math.sqrt(arg)
     override fun power(arg: Double, pow: Number): Double = when {
@@ -109,29 +108,31 @@ public object DoubleField : ExtendedField<Double>, Norm<Double, Double>, ScaleOp
         else -> arg.kpow(pow.toDouble())
     }
 
-    override inline fun exp(arg: Double): Double = kotlin.math.exp(arg)
-    override inline fun ln(arg: Double): Double = kotlin.math.ln(arg)
+    override fun exp(arg: Double): Double = kotlin.math.exp(arg)
+    override fun ln(arg: Double): Double = kotlin.math.ln(arg)
 
-    override inline fun norm(arg: Double): Double = abs(arg)
+    override fun norm(arg: Double): Double = abs(arg)
 
-    override inline fun Double.unaryMinus(): Double = -this
-    override inline fun Double.plus(arg: Double): Double = this + arg
-    override inline fun Double.minus(arg: Double): Double = this - arg
-    override inline fun Double.times(arg: Double): Double = this * arg
-    override inline fun Double.div(arg: Double): Double = this / arg
+    override fun Double.unaryMinus(): Double = -this
+    override fun Double.plus(arg: Double): Double = this + arg
+    override fun Double.minus(arg: Double): Double = this - arg
+    override fun Double.times(arg: Double): Double = this * arg
+    override fun Double.div(arg: Double): Double = this / arg
 }
 
-public val Double.Companion.algebra: DoubleField get() = DoubleField
+public typealias DoubleField = Float64Field
+
+public val Double.Companion.algebra: Float64Field get() = Float64Field
 
 /**
- * A field for [Float] without boxing. Does not produce appropriate field element.
+ * A field for [Float] without boxing. Does not produce an appropriate field element.
  */
-@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE")
-public object FloatField : ExtendedField<Float>, Norm<Float, Float> {
-    override val bufferFactory: MutableBufferFactory<Float> = MutableBufferFactory(::FloatBuffer)
+@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
+public object Float32Field : ExtendedField<Float>, Norm<Float, Float> {
+    override val bufferFactory: MutableBufferFactory<Float> = MutableBufferFactory()
 
-    override inline val zero: Float get() = 0.0f
-    override inline val one: Float get() = 1.0f
+    override val zero: Float get() = 0.0f
+    override val one: Float get() = 1.0f
 
     override fun number(value: Number): Float = value.toFloat()
 
@@ -141,132 +142,142 @@ public object FloatField : ExtendedField<Float>, Norm<Float, Float> {
             else -> super.binaryOperationFunction(operation)
         }
 
-    override inline fun add(left: Float, right: Float): Float = left + right
+    override fun add(left: Float, right: Float): Float = left + right
     override fun scale(a: Float, value: Double): Float = a * value.toFloat()
 
-    override inline fun multiply(left: Float, right: Float): Float = left * right
+    override fun multiply(left: Float, right: Float): Float = left * right
 
-    override inline fun divide(left: Float, right: Float): Float = left / right
+    override fun divide(left: Float, right: Float): Float = left / right
 
-    override inline fun sin(arg: Float): Float = kotlin.math.sin(arg)
-    override inline fun cos(arg: Float): Float = kotlin.math.cos(arg)
-    override inline fun tan(arg: Float): Float = kotlin.math.tan(arg)
-    override inline fun acos(arg: Float): Float = kotlin.math.acos(arg)
-    override inline fun asin(arg: Float): Float = kotlin.math.asin(arg)
-    override inline fun atan(arg: Float): Float = kotlin.math.atan(arg)
+    override fun sin(arg: Float): Float = kotlin.math.sin(arg)
+    override fun cos(arg: Float): Float = kotlin.math.cos(arg)
+    override fun tan(arg: Float): Float = kotlin.math.tan(arg)
+    override fun acos(arg: Float): Float = kotlin.math.acos(arg)
+    override fun asin(arg: Float): Float = kotlin.math.asin(arg)
+    override fun atan(arg: Float): Float = kotlin.math.atan(arg)
 
-    override inline fun sinh(arg: Float): Float = kotlin.math.sinh(arg)
-    override inline fun cosh(arg: Float): Float = kotlin.math.cosh(arg)
-    override inline fun tanh(arg: Float): Float = kotlin.math.tanh(arg)
-    override inline fun asinh(arg: Float): Float = kotlin.math.asinh(arg)
-    override inline fun acosh(arg: Float): Float = kotlin.math.acosh(arg)
-    override inline fun atanh(arg: Float): Float = kotlin.math.atanh(arg)
+    override fun sinh(arg: Float): Float = kotlin.math.sinh(arg)
+    override fun cosh(arg: Float): Float = kotlin.math.cosh(arg)
+    override fun tanh(arg: Float): Float = kotlin.math.tanh(arg)
+    override fun asinh(arg: Float): Float = kotlin.math.asinh(arg)
+    override fun acosh(arg: Float): Float = kotlin.math.acosh(arg)
+    override fun atanh(arg: Float): Float = kotlin.math.atanh(arg)
 
-    override inline fun sqrt(arg: Float): Float = kotlin.math.sqrt(arg)
-    override inline fun power(arg: Float, pow: Number): Float = arg.kpow(pow.toFloat())
+    override fun sqrt(arg: Float): Float = kotlin.math.sqrt(arg)
+    override fun power(arg: Float, pow: Number): Float = arg.kpow(pow.toFloat())
 
-    override inline fun exp(arg: Float): Float = kotlin.math.exp(arg)
-    override inline fun ln(arg: Float): Float = kotlin.math.ln(arg)
+    override fun exp(arg: Float): Float = kotlin.math.exp(arg)
+    override fun ln(arg: Float): Float = kotlin.math.ln(arg)
 
-    override inline fun norm(arg: Float): Float = abs(arg)
+    override fun norm(arg: Float): Float = abs(arg)
 
-    override inline fun Float.unaryMinus(): Float = -this
-    override inline fun Float.plus(arg: Float): Float = this + arg
-    override inline fun Float.minus(arg: Float): Float = this - arg
-    override inline fun Float.times(arg: Float): Float = this * arg
-    override inline fun Float.div(arg: Float): Float = this / arg
+    override fun Float.unaryMinus(): Float = -this
+    override fun Float.plus(arg: Float): Float = this + arg
+    override fun Float.minus(arg: Float): Float = this - arg
+    override fun Float.times(arg: Float): Float = this * arg
+    override fun Float.div(arg: Float): Float = this / arg
 }
 
-public val Float.Companion.algebra: FloatField get() = FloatField
+public typealias FloatField = Float32Field
+
+public val Float.Companion.algebra: Float32Field get() = Float32Field
 
 /**
- * A field for [Int] without boxing. Does not produce corresponding ring element.
+ * A field for [Int] without boxing. Does not produce a corresponding ring element.
  */
-@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE")
-public object IntRing : Ring<Int>, Norm<Int, Int>, NumericAlgebra<Int> {
-    override val bufferFactory: MutableBufferFactory<Int> = MutableBufferFactory(::IntBuffer)
+@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
+public object Int32Ring : Ring<Int>, Norm<Int, Int>, NumericAlgebra<Int> {
+    override val bufferFactory: MutableBufferFactory<Int> = MutableBufferFactory()
 
-    override inline val zero: Int get() = 0
-    override inline val one: Int get() = 1
+    override val zero: Int get() = 0
+    override val one: Int get() = 1
 
     override fun number(value: Number): Int = value.toInt()
-    override inline fun add(left: Int, right: Int): Int = left + right
-    override inline fun multiply(left: Int, right: Int): Int = left * right
-    override inline fun norm(arg: Int): Int = abs(arg)
+    override fun add(left: Int, right: Int): Int = left + right
+    override fun multiply(left: Int, right: Int): Int = left * right
+    override fun norm(arg: Int): Int = abs(arg)
 
-    override inline fun Int.unaryMinus(): Int = -this
-    override inline fun Int.plus(arg: Int): Int = this + arg
-    override inline fun Int.minus(arg: Int): Int = this - arg
-    override inline fun Int.times(arg: Int): Int = this * arg
+    override fun Int.unaryMinus(): Int = -this
+    override fun Int.plus(arg: Int): Int = this + arg
+    override fun Int.minus(arg: Int): Int = this - arg
+    override fun Int.times(arg: Int): Int = this * arg
 }
 
-public val Int.Companion.algebra: IntRing get() = IntRing
+public typealias IntRing = Int32Ring
+
+public val Int.Companion.algebra: Int32Ring get() = Int32Ring
 
 /**
- * A field for [Short] without boxing. Does not produce appropriate ring element.
+ * A field for [Short] without boxing. Does not produce an appropriate ring element.
  */
-@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE")
-public object ShortRing : Ring<Short>, Norm<Short, Short>, NumericAlgebra<Short> {
-    override val bufferFactory: MutableBufferFactory<Short> = MutableBufferFactory(::ShortBuffer)
+@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
+public object Int16Ring : Ring<Short>, Norm<Short, Short>, NumericAlgebra<Short> {
+    override val bufferFactory: MutableBufferFactory<Short> = MutableBufferFactory()
 
-    override inline val zero: Short get() = 0
-    override inline val one: Short get() = 1
+    override val zero: Short get() = 0
+    override val one: Short get() = 1
 
     override fun number(value: Number): Short = value.toShort()
-    override inline fun add(left: Short, right: Short): Short = (left + right).toShort()
-    override inline fun multiply(left: Short, right: Short): Short = (left * right).toShort()
+    override fun add(left: Short, right: Short): Short = (left + right).toShort()
+    override fun multiply(left: Short, right: Short): Short = (left * right).toShort()
     override fun norm(arg: Short): Short = if (arg > 0) arg else (-arg).toShort()
 
-    override inline fun Short.unaryMinus(): Short = (-this).toShort()
-    override inline fun Short.plus(arg: Short): Short = (this + arg).toShort()
-    override inline fun Short.minus(arg: Short): Short = (this - arg).toShort()
-    override inline fun Short.times(arg: Short): Short = (this * arg).toShort()
+    override fun Short.unaryMinus(): Short = (-this).toShort()
+    override fun Short.plus(arg: Short): Short = (this + arg).toShort()
+    override fun Short.minus(arg: Short): Short = (this - arg).toShort()
+    override fun Short.times(arg: Short): Short = (this * arg).toShort()
 }
 
-public val Short.Companion.algebra: ShortRing get() = ShortRing
+public typealias ShortRing = Int16Ring
+
+public val Short.Companion.algebra: Int16Ring get() = Int16Ring
 
 /**
  * A field for [Byte] without boxing. Does not produce appropriate ring element.
  */
-@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE")
-public object ByteRing : Ring<Byte>, Norm<Byte, Byte>, NumericAlgebra<Byte> {
-    override val bufferFactory: MutableBufferFactory<Byte> = MutableBufferFactory(::ByteBuffer)
+@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
+public object Int8Ring : Ring<Byte>, Norm<Byte, Byte>, NumericAlgebra<Byte> {
+    override val bufferFactory: MutableBufferFactory<Byte> = MutableBufferFactory()
 
-    override inline val zero: Byte get() = 0
-    override inline val one: Byte get() = 1
+    override val zero: Byte get() = 0
+    override val one: Byte get() = 1
 
     override fun number(value: Number): Byte = value.toByte()
-    override inline fun add(left: Byte, right: Byte): Byte = (left + right).toByte()
-    override inline fun multiply(left: Byte, right: Byte): Byte = (left * right).toByte()
+    override fun add(left: Byte, right: Byte): Byte = (left + right).toByte()
+    override fun multiply(left: Byte, right: Byte): Byte = (left * right).toByte()
     override fun norm(arg: Byte): Byte = if (arg > 0) arg else (-arg).toByte()
 
-    override inline fun Byte.unaryMinus(): Byte = (-this).toByte()
-    override inline fun Byte.plus(arg: Byte): Byte = (this + arg).toByte()
-    override inline fun Byte.minus(arg: Byte): Byte = (this - arg).toByte()
-    override inline fun Byte.times(arg: Byte): Byte = (this * arg).toByte()
+    override fun Byte.unaryMinus(): Byte = (-this).toByte()
+    override fun Byte.plus(arg: Byte): Byte = (this + arg).toByte()
+    override fun Byte.minus(arg: Byte): Byte = (this - arg).toByte()
+    override fun Byte.times(arg: Byte): Byte = (this * arg).toByte()
 }
 
-public val Byte.Companion.algebra: ByteRing get() = ByteRing
+public typealias ByteRing = Int8Ring
+
+public val Byte.Companion.algebra: Int8Ring get() = Int8Ring
 
 /**
- * A field for [Double] without boxing. Does not produce appropriate ring element.
+ * A field for [Double] without boxing. Does not produce an appropriate ring element.
  */
-@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE")
-public object LongRing : Ring<Long>, Norm<Long, Long>, NumericAlgebra<Long> {
-    override val bufferFactory: MutableBufferFactory<Long> = MutableBufferFactory(::LongBuffer)
+@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
+public object Int64Ring : Ring<Long>, Norm<Long, Long>, NumericAlgebra<Long> {
+    override val bufferFactory: MutableBufferFactory<Long> = MutableBufferFactory()
 
-    override inline val zero: Long get() = 0L
-    override inline val one: Long get() = 1L
+    override val zero: Long get() = 0L
+    override val one: Long get() = 1L
 
     override fun number(value: Number): Long = value.toLong()
-    override inline fun add(left: Long, right: Long): Long = left + right
-    override inline fun multiply(left: Long, right: Long): Long = left * right
+    override fun add(left: Long, right: Long): Long = left + right
+    override fun multiply(left: Long, right: Long): Long = left * right
     override fun norm(arg: Long): Long = abs(arg)
 
-    override inline fun Long.unaryMinus(): Long = (-this)
-    override inline fun Long.plus(arg: Long): Long = (this + arg)
-    override inline fun Long.minus(arg: Long): Long = (this - arg)
-    override inline fun Long.times(arg: Long): Long = (this * arg)
+    override fun Long.unaryMinus(): Long = (-this)
+    override fun Long.plus(arg: Long): Long = (this + arg)
+    override fun Long.minus(arg: Long): Long = (this - arg)
+    override fun Long.times(arg: Long): Long = (this * arg)
 }
 
-public val Long.Companion.algebra: LongRing get() = LongRing
+public typealias LongRing = Int64Ring
+
+public val Long.Companion.algebra: Int64Ring get() = Int64Ring
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt
index 8e81dd941..15f4077d5 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt
@@ -1,17 +1,20 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.structures
 
+import kotlin.jvm.JvmInline
+
 /**
  * [MutableBuffer] implementation over [Array].
  *
  * @param T the type of elements contained in the buffer.
  * @property array The underlying array.
  */
-public class ArrayBuffer<T>(internal val array: Array<T>) : MutableBuffer<T> {
+@JvmInline
+public value class ArrayBuffer<T>(internal val array: Array<T>) : MutableBuffer<T> {
     // Can't inline because array is invariant
     override val size: Int get() = array.size
 
@@ -22,13 +25,11 @@ public class ArrayBuffer<T>(internal val array: Array<T>) : MutableBuffer<T> {
     }
 
     override operator fun iterator(): Iterator<T> = array.iterator()
-    override fun copy(): MutableBuffer<T> = ArrayBuffer(array.copyOf())
 
     override fun toString(): String = Buffer.toString(this)
 }
 
-
 /**
  * Returns an [ArrayBuffer] that wraps the original array.
  */
-public fun <T> Array<T>.asBuffer(): ArrayBuffer<T> = ArrayBuffer(this)
\ No newline at end of file
+public fun <T> Array<T>.asBuffer(): ArrayBuffer<T> = ArrayBuffer(this)
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt
index cef8d1d4d..7fc06c43e 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt
@@ -1,49 +1,64 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.structures
 
+import space.kscience.attributes.SafeType
+import space.kscience.attributes.WithType
+import space.kscience.attributes.safeTypeOf
 import space.kscience.kmath.operations.WithSize
 import space.kscience.kmath.operations.asSequence
-import kotlin.jvm.JvmInline
-import kotlin.reflect.KClass
+import kotlin.reflect.typeOf
 
 /**
  * Function that produces [Buffer] from its size and function that supplies values.
  *
  * @param T the type of buffer.
  */
-public fun interface BufferFactory<T> {
+public interface BufferFactory<T> : WithType<T> {
+
     public operator fun invoke(size: Int, builder: (Int) -> T): Buffer<T>
-
-    public companion object{
-        public inline fun <reified T : Any> auto(): BufferFactory<T> =
-            BufferFactory(Buffer.Companion::auto)
-
-        public fun <T> boxing(): BufferFactory<T> =
-            BufferFactory(Buffer.Companion::boxing)
-    }
 }
 
+/**
+ * Create a [BufferFactory] for given [type], using primitive storage if possible
+ */
+public fun <T> BufferFactory(type: SafeType<T>): BufferFactory<T> = object : BufferFactory<T> {
+    override val type: SafeType<T> = type
+    override fun invoke(size: Int, builder: (Int) -> T): Buffer<T> = Buffer(type, size, builder)
+}
+
+/**
+ * Create [BufferFactory] using the reified type
+ */
+public inline fun <reified T> BufferFactory(): BufferFactory<T> = BufferFactory(safeTypeOf())
+
 /**
  * Function that produces [MutableBuffer] from its size and function that supplies values.
  *
  * @param T the type of buffer.
  */
-public fun interface MutableBufferFactory<T> : BufferFactory<T> {
+public interface MutableBufferFactory<T> : BufferFactory<T> {
     override fun invoke(size: Int, builder: (Int) -> T): MutableBuffer<T>
 
-    public companion object {
-        public inline fun <reified T : Any> auto(): MutableBufferFactory<T> =
-            MutableBufferFactory(MutableBuffer.Companion::auto)
-
-        public fun <T> boxing(): MutableBufferFactory<T> =
-            MutableBufferFactory(MutableBuffer.Companion::boxing)
-    }
+    public companion object
 }
 
+/**
+ * Create a [MutableBufferFactory] for given [type], using primitive storage if possible
+ */
+public fun <T> MutableBufferFactory(type: SafeType<T>): MutableBufferFactory<T> = object : MutableBufferFactory<T> {
+    override val type: SafeType<T> = type
+    override fun invoke(size: Int, builder: (Int) -> T): MutableBuffer<T> = MutableBuffer(type, size, builder)
+}
+
+/**
+ * Create [BufferFactory] using the reified type
+ */
+public inline fun <reified T> MutableBufferFactory(): MutableBufferFactory<T> = MutableBufferFactory(safeTypeOf())
+
 /**
  * A generic read-only random-access structure for both primitives and objects.
  *
@@ -58,7 +73,7 @@ public interface Buffer<out T> : WithSize {
     override val size: Int
 
     /**
-     * Gets element at given index.
+     * Gets an element at given index.
      */
     public operator fun get(index: Int): T
 
@@ -85,38 +100,46 @@ public interface Buffer<out T> : WithSize {
             return true
         }
 
-        /**
-         * Creates a [ListBuffer] of given type [T] with given [size]. Each element is calculated by calling the
-         * specified [initializer] function.
-         */
-        public inline fun <T> boxing(size: Int, initializer: (Int) -> T): Buffer<T> =
-            List(size, initializer).asBuffer()
+    }
+}
 
-        /**
-         * Creates a [Buffer] of given [type]. If the type is primitive, specialized buffers are used ([IntBuffer],
-         * [DoubleBuffer], etc.), [ListBuffer] is returned otherwise.
-         *
-         * The [size] is specified, and each element is calculated by calling the specified [initializer] function.
-         */
-        @Suppress("UNCHECKED_CAST")
-        public inline fun <T : Any> auto(type: KClass<T>, size: Int, initializer: (Int) -> T): Buffer<T> =
-            when (type) {
-                Double::class -> MutableBuffer.double(size) { initializer(it) as Double } as Buffer<T>
-                Short::class -> MutableBuffer.short(size) { initializer(it) as Short } as Buffer<T>
-                Int::class -> MutableBuffer.int(size) { initializer(it) as Int } as Buffer<T>
-                Long::class -> MutableBuffer.long(size) { initializer(it) as Long } as Buffer<T>
-                Float::class -> MutableBuffer.float(size) { initializer(it) as Float } as Buffer<T>
-                else -> boxing(size, initializer)
-            }
+/**
+ * Creates a [Buffer] of given [type]. If the type is primitive, specialized buffers are used ([Int32Buffer],
+ * [Float64Buffer], etc.), [ListBuffer] is returned otherwise.
+ *
+ * The [size] is specified, and each element is calculated by calling the specified [initializer] function.
+ */
+@Suppress("UNCHECKED_CAST", "DuplicatedCode")
+public fun <T> Buffer(
+    type: SafeType<T>,
+    size: Int,
+    initializer: (Int) -> T,
+): Buffer<T> = when (type.kType) {
+    typeOf<Double>() -> MutableBuffer.double(size) { initializer(it) as Double } as Buffer<T>
+    typeOf<Short>() -> MutableBuffer.short(size) { initializer(it) as Short } as Buffer<T>
+    typeOf<Int>() -> MutableBuffer.int(size) { initializer(it) as Int } as Buffer<T>
+    typeOf<Long>() -> MutableBuffer.long(size) { initializer(it) as Long } as Buffer<T>
+    typeOf<Float>() -> MutableBuffer.float(size) { initializer(it) as Float } as Buffer<T>
+    else -> List(size, initializer).asBuffer()
+}
 
-        /**
-         * Creates a [Buffer] of given type [T]. If the type is primitive, specialized buffers are used ([IntBuffer],
-         * [DoubleBuffer], etc.), [ListBuffer] is returned otherwise.
-         *
-         * The [size] is specified, and each element is calculated by calling the specified [initializer] function.
-         */
-        public inline fun <reified T : Any> auto(size: Int, initializer: (Int) -> T): Buffer<T> =
-            auto(T::class, size, initializer)
+/**
+ * Creates a [Buffer] of given type [T]. If the type is primitive, specialized buffers are used ([Int32Buffer],
+ * [Float64Buffer], etc.), [ListBuffer] is returned otherwise.
+ *
+ * The [size] is specified, and each element is calculated by calling the specified [initializer] function.
+ */
+@Suppress("UNCHECKED_CAST", "DuplicatedCode")
+public inline fun <reified T> Buffer(size: Int, initializer: (Int) -> T): Buffer<T> {
+    //code duplication here because we want to inline initializers
+    val type = safeTypeOf<T>()
+    return when (type.kType) {
+        typeOf<Double>() -> MutableBuffer.double(size) { initializer(it) as Double } as Buffer<T>
+        typeOf<Short>() -> MutableBuffer.short(size) { initializer(it) as Short } as Buffer<T>
+        typeOf<Int>() -> MutableBuffer.int(size) { initializer(it) as Int } as Buffer<T>
+        typeOf<Long>() -> MutableBuffer.long(size) { initializer(it) as Long } as Buffer<T>
+        typeOf<Float>() -> MutableBuffer.float(size) { initializer(it) as Float } as Buffer<T>
+        else -> List(size, initializer).asBuffer()
     }
 }
 
@@ -142,28 +165,16 @@ public fun <T> Buffer<T>.last(): T {
     return get(size - 1)
 }
 
-/**
- * Immutable wrapper for [MutableBuffer].
- *
- * @param T the type of elements contained in the buffer.
- * @property buffer The underlying buffer.
- */
-@JvmInline
-public value class ReadOnlyBuffer<T>(public val buffer: MutableBuffer<T>) : Buffer<T> {
-    override val size: Int get() = buffer.size
-
-    override operator fun get(index: Int): T = buffer[index]
-
-    override operator fun iterator(): Iterator<T> = buffer.iterator()
-}
-
 /**
  * A buffer with content calculated on-demand. The calculated content is not stored, so it is recalculated on each call.
- * Useful when one needs single element from the buffer.
+ * Useful when one needs a single element from the buffer.
  *
  * @param T the type of elements provided by the buffer.
  */
-public class VirtualBuffer<out T>(override val size: Int, private val generator: (Int) -> T) : Buffer<T> {
+public class VirtualBuffer<out T>(
+    override val size: Int,
+    private val generator: (Int) -> T,
+) : Buffer<T> {
     override operator fun get(index: Int): T {
         if (index < 0 || index >= size) throw IndexOutOfBoundsException("Expected index from 0 to ${size - 1}, but found $index")
         return generator(index)
@@ -173,8 +184,3 @@ public class VirtualBuffer<out T>(override val size: Int, private val generator:
 
     override fun toString(): String = Buffer.toString(this)
 }
-
-/**
- * Convert this buffer to read-only buffer.
- */
-public fun <T> Buffer<T>.asReadOnly(): Buffer<T> = if (this is MutableBuffer) ReadOnlyBuffer(this) else this
\ No newline at end of file
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt
index 48f3e919b..32990c707 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt
@@ -1,11 +1,11 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.structures
 
-import space.kscience.kmath.nd.*
+import space.kscience.kmath.nd.Structure2D
 
 /**
  * A context that allows to operate on a [MutableBuffer] as on 2d array
@@ -26,15 +26,13 @@ internal class BufferAccessor2D<T>(
 
     fun create(mat: Structure2D<T>): MutableBuffer<T> = create { i, j -> mat[i, j] }
 
-    //TODO optimize wrapper
-    fun MutableBuffer<T>.collect(): Structure2D<T> = StructureND.buffered(
-        ColumnStrides(ShapeND(rowNum, colNum)),
-        factory
-    ) { (i, j) ->
-        get(i, j)
-    }.as2D()
+//    //TODO optimize wrapper
+//    fun MutableBuffer<T>.toStructure2D(): Structure2D<T> = BufferND(
+//        type, ShapeND(rowNum, colNum)
+//    ) { (i, j) -> get(i, j) }.as2D()
 
     inner class Row(val buffer: MutableBuffer<T>, val rowIndex: Int) : MutableBuffer<T> {
+
         override val size: Int get() = colNum
 
         override operator fun get(index: Int): T = buffer[rowIndex, index]
@@ -43,7 +41,6 @@ internal class BufferAccessor2D<T>(
             buffer[rowIndex, index] = value
         }
 
-        override fun copy(): MutableBuffer<T> = factory(colNum) { get(it) }
         override operator fun iterator(): Iterator<T> = (0 until colNum).map(::get).iterator()
 
         override fun toString(): String = Buffer.toString(this)
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferList.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferList.kt
new file mode 100644
index 000000000..ff668589e
--- /dev/null
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferList.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018-2023 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.structures
+
+import kotlin.jvm.JvmInline
+
+@JvmInline
+private value class BufferList<T>(val buffer: Buffer<T>) : List<T> {
+    override val size: Int get() = buffer.size
+
+    override fun get(index: Int): T = buffer[index]
+
+    override fun isEmpty(): Boolean = buffer.size == 0
+
+    override fun iterator(): Iterator<T> = buffer.iterator()
+
+    override fun listIterator(index: Int): ListIterator<T> = object : ListIterator<T> {
+        var currentIndex = index
+
+        override fun hasNext(): Boolean = currentIndex < buffer.size - 1
+
+        override fun hasPrevious(): Boolean = currentIndex > 0
+
+        override fun next(): T {
+            if (!hasNext()) throw NoSuchElementException()
+            return get(currentIndex++)
+        }
+
+        override fun nextIndex(): Int = currentIndex
+
+        override fun previous(): T {
+            if (!hasPrevious()) throw NoSuchElementException()
+            return get(--currentIndex)
+        }
+
+        override fun previousIndex(): Int = currentIndex - 1
+
+    }
+
+    override fun listIterator(): ListIterator<T> = listIterator(0)
+
+    override fun subList(fromIndex: Int, toIndex: Int): List<T> =
+        buffer.slice(fromIndex..toIndex).asList()
+
+    override fun lastIndexOf(element: T): Int {
+        for (i in buffer.indices.reversed()) {
+            if (buffer[i] == element) return i
+        }
+        return -1
+    }
+
+    override fun indexOf(element: T): Int {
+        for (i in buffer.indices) {
+            if (buffer[i] == element) return i
+        }
+        return -1
+    }
+
+    override fun containsAll(elements: Collection<T>): Boolean {
+        val remainingElements = HashSet(elements)
+        for (e in buffer) {
+            if (e in remainingElements) {
+                remainingElements.remove(e)
+            }
+            if (remainingElements.isEmpty()) {
+                return true
+            }
+        }
+        return false
+    }
+
+    override fun contains(element: T): Boolean = indexOf(element) >= 0
+}
+
+/**
+ * Returns a zero-copy list that reflects the content of the buffer.
+ */
+public fun <T> Buffer<T>.asList(): List<T> = BufferList(this)
\ No newline at end of file
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferView.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferView.kt
index 02fd2600d..180098f51 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferView.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferView.kt
@@ -1,3 +1,8 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
 package space.kscience.kmath.structures
 
 import space.kscience.kmath.UnstableKMathAPI
@@ -36,6 +41,7 @@ public class BufferSlice<T>(
         }
     }
 
+
     override fun get(index: Int): T = if (index >= size) {
         throw IndexOutOfBoundsException("$index is out of ${0 until size} rage")
     } else {
@@ -96,6 +102,13 @@ public fun <T> Buffer<T>.slice(range: IntRange): BufferView<T> = if (this is Buf
     )
 }
 
+/**
+ *  Dynamically create a range from the initial range
+ */
+@UnstableKMathAPI
+public inline fun <T> Buffer<T>.slice(rangeBuilder: IntRange.() -> IntRange): BufferView<T> =
+    slice(rangeBuilder(indices))
+
 /**
  * Resize original buffer to a given range using given [range], filling additional segments with [defaultValue].
  * Range left border could be negative to designate adding new blank segment to the beginning of the buffer
@@ -174,9 +187,7 @@ public class PermutedMutableBuffer<T>(
         origin[permutations[index]] = value
     }
 
-    override fun copy(): MutableBuffer<T> = PermutedMutableBuffer(origin.copy(), permutations)
     //TODO Probably could be optimized
-
     override fun iterator(): Iterator<T> = permutations.asSequence().map { origin[it] }.iterator()
 
     @UnstableKMathAPI
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt
deleted file mode 100644
index 1696d5055..000000000
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2018-2022 KMath contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package space.kscience.kmath.structures
-
-import space.kscience.kmath.operations.BufferTransform
-import kotlin.jvm.JvmInline
-
-/**
- * Specialized [MutableBuffer] implementation over [DoubleArray].
- *
- * @property array the underlying array.
- */
-@JvmInline
-public value class DoubleBuffer(public val array: DoubleArray) : PrimitiveBuffer<Double> {
-    override val size: Int get() = array.size
-
-    override operator fun get(index: Int): Double = array[index]
-
-    override operator fun set(index: Int, value: Double) {
-        array[index] = value
-    }
-
-    override operator fun iterator(): DoubleIterator = array.iterator()
-
-    override fun copy(): DoubleBuffer = DoubleBuffer(array.copyOf())
-
-    override fun toString(): String = Buffer.toString(this)
-
-    public companion object {
-        public fun zero(size: Int): DoubleBuffer = DoubleArray(size).asBuffer()
-    }
-}
-
-/**
- * Creates a new [DoubleBuffer] with the specified [size], where each element is calculated by calling the specified
- * [init] function.
- *
- * The function [init] is called for each array element sequentially starting from the first one.
- * 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) })
-
-/**
- * Returns a new [DoubleBuffer] of given elements.
- */
-public fun DoubleBuffer(vararg doubles: Double): DoubleBuffer = DoubleBuffer(doubles)
-
-/**
- * Returns a new [DoubleArray] containing all the elements of this [Buffer].
- */
-public fun Buffer<Double>.toDoubleArray(): DoubleArray = when (this) {
-    is DoubleBuffer -> array
-    else -> DoubleArray(size, ::get)
-}
-
-/**
- * Represent this buffer as [DoubleBuffer]. Does not guarantee that changes in the original buffer are reflected on this buffer.
- */
-public fun Buffer<Double>.toDoubleBuffer(): DoubleBuffer = when (this) {
-    is DoubleBuffer -> this
-    else -> DoubleArray(size, ::get).asBuffer()
-}
-
-/**
- * Returns [DoubleBuffer] over this array.
- *
- * @receiver the array.
- * @return the new buffer.
- */
-public fun DoubleArray.asBuffer(): DoubleBuffer = DoubleBuffer(this)
-
-
-public fun interface DoubleBufferTransform : BufferTransform<Double, Double> {
-    public fun transform(arg: DoubleBuffer): DoubleBuffer
-
-    override fun transform(arg: Buffer<Double>): DoubleBuffer = arg.toDoubleBuffer()
-}
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt
index d99e02996..043d65cd4 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -55,8 +55,9 @@ public fun FlaggedBuffer<*>.isMissing(index: Int): Boolean = hasFlag(index, Valu
  */
 public class FlaggedDoubleBuffer(
     public val values: DoubleArray,
-    public val flags: ByteArray
+    public val flags: ByteArray,
 ) : FlaggedBuffer<Double?>, Buffer<Double?> {
+
     init {
         require(values.size == flags.size) { "Values and flags must have the same dimensions" }
     }
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Float32Buffer.kt
similarity index 60%
rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt
rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Float32Buffer.kt
index f1533ee3a..a6b27e7a7 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Float32Buffer.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -14,7 +14,8 @@ import kotlin.jvm.JvmInline
  * @author Iaroslav Postovalov
  */
 @JvmInline
-public value class FloatBuffer(public val array: FloatArray) : PrimitiveBuffer<Float> {
+public value class Float32Buffer(public val array: FloatArray) : PrimitiveBuffer<Float> {
+
     override val size: Int get() = array.size
 
     override operator fun get(index: Int): Float = array[index]
@@ -25,36 +26,37 @@ public value class FloatBuffer(public val array: FloatArray) : PrimitiveBuffer<F
 
     override operator fun iterator(): FloatIterator = array.iterator()
 
-    override fun copy(): MutableBuffer<Float> =
-        FloatBuffer(array.copyOf())
 }
 
+public typealias FloatBuffer = Float32Buffer
+
 /**
- * Creates a new [FloatBuffer] with the specified [size], where each element is calculated by calling the specified
+ * Creates a new [Float32Buffer] with the specified [size], where each element is calculated by calling the specified
  * [init] function.
  *
  * The function [init] is called for each array element sequentially starting from the first one.
  * 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 Float32Buffer(size: Int, init: (Int) -> Float): Float32Buffer =
+    Float32Buffer(FloatArray(size) { init(it) })
 
 /**
- * Returns a new [FloatBuffer] of given elements.
+ * Returns a new [Float32Buffer] of given elements.
  */
-public fun FloatBuffer(vararg floats: Float): FloatBuffer = FloatBuffer(floats)
+public fun Float32Buffer(vararg floats: Float): Float32Buffer = Float32Buffer(floats)
 
 /**
  * Returns a new [FloatArray] containing all the elements of this [Buffer].
  */
 public fun Buffer<Float>.toFloatArray(): FloatArray = when (this) {
-    is FloatBuffer -> array.copyOf()
+    is Float32Buffer -> array.copyOf()
     else -> FloatArray(size, ::get)
 }
 
 /**
- * Returns [FloatBuffer] over this array.
+ * Returns [Float32Buffer] over this array.
  *
  * @receiver the array.
  * @return the new buffer.
  */
-public fun FloatArray.asBuffer(): FloatBuffer = FloatBuffer(this)
+public fun FloatArray.asBuffer(): Float32Buffer = Float32Buffer(this)
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Float64Buffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Float64Buffer.kt
new file mode 100644
index 000000000..38b737fd5
--- /dev/null
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Float64Buffer.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.structures
+
+import space.kscience.kmath.operations.BufferTransform
+import kotlin.jvm.JvmInline
+
+/**
+ * Specialized [MutableBuffer] implementation over [DoubleArray].
+ *
+ * @property array the underlying array.
+ */
+@JvmInline
+public value class Float64Buffer(public val array: DoubleArray) : PrimitiveBuffer<Double> {
+
+    override val size: Int get() = array.size
+
+    override operator fun get(index: Int): Double = array[index]
+
+    override operator fun set(index: Int, value: Double) {
+        array[index] = value
+    }
+
+    override operator fun iterator(): DoubleIterator = array.iterator()
+
+    override fun toString(): String = Buffer.toString(this)
+
+    public companion object {
+        public fun zero(size: Int): Float64Buffer = DoubleArray(size).asBuffer()
+    }
+}
+
+@Deprecated("Use Float64Buffer instead", ReplaceWith("Float64Buffer"))
+public typealias DoubleBuffer = Float64Buffer
+
+/**
+ * Creates a new [Float64Buffer] with the specified [size], where each element is calculated by calling the specified
+ * [init] function.
+ *
+ * The function [init] is called for each array element sequentially starting from the first one.
+ * It should return the value for a buffer element given its index.
+ */
+public inline fun Float64Buffer(size: Int, init: (Int) -> Double): Float64Buffer =
+    Float64Buffer(DoubleArray(size) { init(it) })
+
+/**
+ * Returns a new [Float64Buffer] of given elements.
+ */
+public fun Float64Buffer(vararg doubles: Double): Float64Buffer = Float64Buffer(doubles)
+
+/**
+ * Returns a new [DoubleArray] containing all the elements of this [Buffer].
+ */
+public fun Buffer<Double>.toDoubleArray(): DoubleArray = when (this) {
+    is Float64Buffer -> array
+    else -> DoubleArray(size, ::get)
+}
+
+/**
+ * Represent this buffer as [Float64Buffer]. Does not guarantee that changes in the original buffer are reflected on this buffer.
+ */
+public fun Buffer<Double>.toFloat64Buffer(): Float64Buffer = when (this) {
+    is Float64Buffer -> this
+    else -> DoubleArray(size, ::get).asBuffer()
+}
+
+/**
+ * Returns [Float64Buffer] over this array.
+ *
+ * @receiver the array.
+ * @return the new buffer.
+ */
+public fun DoubleArray.asBuffer(): Float64Buffer = Float64Buffer(this)
+
+
+public fun interface Float64BufferTransform : BufferTransform<Double, Double> {
+    public fun transform(arg: Float64Buffer): Float64Buffer
+
+    override fun transform(arg: Buffer<Double>): Float64Buffer = arg.toFloat64Buffer()
+}
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Int16Buffer.kt
similarity index 63%
rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt
rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Int16Buffer.kt
index 7dbb2b58e..9ceeeec05 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Int16Buffer.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -13,7 +13,9 @@ import kotlin.jvm.JvmInline
  * @property array the underlying array.
  */
 @JvmInline
-public value class ShortBuffer(public val array: ShortArray) : MutableBuffer<Short> {
+public value class Int16Buffer(public val array: ShortArray) : MutableBuffer<Short> {
+
+
     override val size: Int get() = array.size
 
     override operator fun get(index: Int): Short = array[index]
@@ -23,35 +25,36 @@ public value class ShortBuffer(public val array: ShortArray) : MutableBuffer<Sho
     }
 
     override operator fun iterator(): ShortIterator = array.iterator()
-    override fun copy(): MutableBuffer<Short> = ShortBuffer(array.copyOf())
 }
 
+public typealias ShortBuffer = Int16Buffer
+
 /**
- * Creates a new [ShortBuffer] with the specified [size], where each element is calculated by calling the specified
+ * Creates a new [Int16Buffer] with the specified [size], where each element is calculated by calling the specified
  * [init] function.
  *
  * The function [init] is called for each array element sequentially starting from the first one.
  * 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 Int16Buffer(size: Int, init: (Int) -> Short): Int16Buffer = Int16Buffer(ShortArray(size) { init(it) })
 
 /**
- * Returns a new [ShortBuffer] of given elements.
+ * Returns a new [Int16Buffer] of given elements.
  */
-public fun ShortBuffer(vararg shorts: Short): ShortBuffer = ShortBuffer(shorts)
+public fun Int16Buffer(vararg shorts: Short): Int16Buffer = Int16Buffer(shorts)
 
 /**
  * Returns a new [ShortArray] containing all the elements of this [Buffer].
  */
 public fun Buffer<Short>.toShortArray(): ShortArray = when (this) {
-    is ShortBuffer -> array.copyOf()
+    is Int16Buffer -> array.copyOf()
     else -> ShortArray(size, ::get)
 }
 
 /**
- * Returns [ShortBuffer] over this array.
+ * Returns [Int16Buffer] over this array.
  *
  * @receiver the array.
  * @return the new buffer.
  */
-public fun ShortArray.asBuffer(): ShortBuffer = ShortBuffer(this)
+public fun ShortArray.asBuffer(): Int16Buffer = Int16Buffer(this)
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Int32Buffer.kt
similarity index 60%
rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt
rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Int32Buffer.kt
index 0de7119b1..bb41c2b9b 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Int32Buffer.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -13,7 +13,9 @@ import kotlin.jvm.JvmInline
  * @property array the underlying array.
  */
 @JvmInline
-public value class IntBuffer(public val array: IntArray) : PrimitiveBuffer<Int> {
+public value class Int32Buffer(public val array: IntArray) : PrimitiveBuffer<Int> {
+
+
     override val size: Int get() = array.size
 
     override operator fun get(index: Int): Int = array[index]
@@ -24,35 +26,36 @@ public value class IntBuffer(public val array: IntArray) : PrimitiveBuffer<Int>
 
     override operator fun iterator(): IntIterator = array.iterator()
 
-    override fun copy(): IntBuffer = IntBuffer(array.copyOf())
 }
 
+public typealias IntBuffer = Int32Buffer
+
 /**
- * Creates a new [IntBuffer] with the specified [size], where each element is calculated by calling the specified
+ * Creates a new [Int32Buffer] with the specified [size], where each element is calculated by calling the specified
  * [init] function.
  *
  * The function [init] is called for each array element sequentially starting from the first one.
  * 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 Int32Buffer(size: Int, init: (Int) -> Int): Int32Buffer = Int32Buffer(IntArray(size) { init(it) })
 
 /**
- * Returns a new [IntBuffer] of given elements.
+ * Returns a new [Int32Buffer] of given elements.
  */
-public fun IntBuffer(vararg ints: Int): IntBuffer = IntBuffer(ints)
+public fun Int32Buffer(vararg ints: Int): Int32Buffer = Int32Buffer(ints)
 
 /**
  * Returns a new [IntArray] containing all the elements of this [Buffer].
  */
 public fun Buffer<Int>.toIntArray(): IntArray = when (this) {
-    is IntBuffer -> array.copyOf()
+    is Int32Buffer -> array.copyOf()
     else -> IntArray(size, ::get)
 }
 
 /**
- * Returns [IntBuffer] over this array.
+ * Returns [Int32Buffer] over this array.
  *
  * @receiver the array.
  * @return the new buffer.
  */
-public fun IntArray.asBuffer(): IntBuffer = IntBuffer(this)
+public fun IntArray.asBuffer(): Int32Buffer = Int32Buffer(this)
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Int64Buffer.kt
similarity index 59%
rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt
rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Int64Buffer.kt
index 9f77fc9d8..ee1bf2d56 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Int64Buffer.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -13,7 +13,8 @@ import kotlin.jvm.JvmInline
  * @property array the underlying array.
  */
 @JvmInline
-public value class LongBuffer(public val array: LongArray) : PrimitiveBuffer<Long> {
+public value class Int64Buffer(public val array: LongArray) : PrimitiveBuffer<Long> {
+
     override val size: Int get() = array.size
 
     override operator fun get(index: Int): Long = array[index]
@@ -24,36 +25,36 @@ public value class LongBuffer(public val array: LongArray) : PrimitiveBuffer<Lon
 
     override operator fun iterator(): LongIterator = array.iterator()
 
-    override fun copy(): MutableBuffer<Long> =
-        LongBuffer(array.copyOf())
 }
 
+public typealias LongBuffer = Int64Buffer
+
 /**
- * Creates a new [LongBuffer] with the specified [size], where each element is calculated by calling the specified
+ * Creates a new [Int64Buffer] with the specified [size], where each element is calculated by calling the specified
  * [init] function.
  *
  * The function [init] is called for each array element sequentially starting from the first one.
  * 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 Int64Buffer(size: Int, init: (Int) -> Long): Int64Buffer = Int64Buffer(LongArray(size) { init(it) })
 
 /**
- * Returns a new [LongBuffer] of given elements.
+ * Returns a new [Int64Buffer] of given elements.
  */
-public fun LongBuffer(vararg longs: Long): LongBuffer = LongBuffer(longs)
+public fun Int64Buffer(vararg longs: Long): Int64Buffer = Int64Buffer(longs)
 
 /**
  * Returns a new [LongArray] containing all the elements of this [Buffer].
  */
 public fun Buffer<Long>.toLongArray(): LongArray = when (this) {
-    is LongBuffer -> array.copyOf()
+    is Int64Buffer -> array.copyOf()
     else -> LongArray(size, ::get)
 }
 
 /**
- * Returns [LongBuffer] over this array.
+ * Returns [Int64Buffer] over this array.
  *
  * @receiver the array.
  * @return the new buffer.
  */
-public fun LongArray.asBuffer(): LongBuffer = LongBuffer(this)
+public fun LongArray.asBuffer(): Int64Buffer = Int64Buffer(this)
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ByteBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Int8Buffer.kt
similarity index 64%
rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ByteBuffer.kt
rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Int8Buffer.kt
index 2be17c5e4..c7b1d43c5 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ByteBuffer.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Int8Buffer.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -13,7 +13,8 @@ import kotlin.jvm.JvmInline
  * @property array the underlying array.
  */
 @JvmInline
-public value class ByteBuffer(public val array: ByteArray) : MutableBuffer<Byte> {
+public value class Int8Buffer(public val array: ByteArray) : MutableBuffer<Byte> {
+
     override val size: Int get() = array.size
 
     override operator fun get(index: Int): Byte = array[index]
@@ -23,35 +24,34 @@ public value class ByteBuffer(public val array: ByteArray) : MutableBuffer<Byte>
     }
 
     override operator fun iterator(): ByteIterator = array.iterator()
-    override fun copy(): MutableBuffer<Byte> = ByteBuffer(array.copyOf())
 }
 
 /**
- * Creates a new [ByteBuffer] with the specified [size], where each element is calculated by calling the specified
+ * Creates a new [Int8Buffer] with the specified [size], where each element is calculated by calling the specified
  * [init] function.
  *
  * The function [init] is called for each array element sequentially starting from the first one.
  * It should return the value for a buffer element given its index.
  */
-public inline fun ByteBuffer(size: Int, init: (Int) -> Byte): ByteBuffer = ByteBuffer(ByteArray(size) { init(it) })
+public inline fun Int8Buffer(size: Int, init: (Int) -> Byte): Int8Buffer = Int8Buffer(ByteArray(size) { init(it) })
 
 /**
- * Returns a new [ByteBuffer] of given elements.
+ * Returns a new [Int8Buffer] of given elements.
  */
-public fun ByteBuffer(vararg bytes: Byte): ByteBuffer = ByteBuffer(bytes)
+public fun Int8Buffer(vararg bytes: Byte): Int8Buffer = Int8Buffer(bytes)
 
 /**
  * Returns a new [ByteArray] containing all the elements of this [Buffer].
  */
 public fun Buffer<Byte>.toByteArray(): ByteArray = when (this) {
-    is ByteBuffer -> array.copyOf()
+    is Int8Buffer -> array.copyOf()
     else -> ByteArray(size, ::get)
 }
 
 /**
- * Returns [ByteBuffer] over this array.
+ * Returns [Int8Buffer] over this array.
  *
  * @receiver the array.
  * @return the new buffer.
  */
-public fun ByteArray.asBuffer(): ByteBuffer = ByteBuffer(this)
+public fun ByteArray.asBuffer(): Int8Buffer = Int8Buffer(this)
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt
index fbc9a489b..501bd1c64 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt
@@ -1,12 +1,10 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.structures
 
-import kotlin.jvm.JvmInline
-
 /**
  * [Buffer] implementation over [List].
  *
@@ -15,8 +13,6 @@ import kotlin.jvm.JvmInline
  */
 public class ListBuffer<T>(public val list: List<T>) : Buffer<T> {
 
-    public constructor(size: Int, initializer: (Int) -> T) : this(List(size, initializer))
-
     override val size: Int get() = list.size
 
     override operator fun get(index: Int): T = list[index]
@@ -37,10 +33,7 @@ public fun <T> List<T>.asBuffer(): ListBuffer<T> = ListBuffer(this)
  * @param T the type of elements contained in the buffer.
  * @property list The underlying list.
  */
-@JvmInline
-public value class MutableListBuffer<T>(public val list: MutableList<T>) : MutableBuffer<T> {
-
-    public constructor(size: Int, initializer: (Int) -> T) : this(MutableList(size, initializer))
+public class MutableListBuffer<T>(public val list: MutableList<T>) : MutableBuffer<T> {
 
     override val size: Int get() = list.size
 
@@ -51,10 +44,12 @@ public value class MutableListBuffer<T>(public val list: MutableList<T>) : Mutab
     }
 
     override operator fun iterator(): Iterator<T> = list.iterator()
-    override fun copy(): MutableBuffer<T> = MutableListBuffer(ArrayList(list))
+
+    override fun toString(): String = Buffer.toString(this)
 }
 
+
 /**
  * Returns an [MutableListBuffer] that wraps the original list.
  */
-public fun <T> MutableList<T>.asMutableBuffer(): MutableListBuffer<T> = MutableListBuffer(this)
+public fun <T> MutableList<T>.asMutableBuffer(): MutableListBuffer<T> = MutableListBuffer(this)
\ No newline at end of file
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt
index c0bfc6ecc..eeee5faad 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt
@@ -1,11 +1,13 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.structures
 
-import kotlin.reflect.KClass
+import space.kscience.attributes.SafeType
+import space.kscience.attributes.safeTypeOf
+import kotlin.reflect.typeOf
 
 /**
  * A generic mutable random-access structure for both primitives and objects.
@@ -13,88 +15,103 @@ import kotlin.reflect.KClass
  * @param T the type of elements contained in the buffer.
  */
 public interface MutableBuffer<T> : Buffer<T> {
+
     /**
      * Sets the array element at the specified [index] to the specified [value].
      */
     public operator fun set(index: Int, value: T)
 
-    /**
-     * Returns a shallow copy of the buffer.
-     */
-    public fun copy(): MutableBuffer<T>
 
     public companion object {
         /**
-         * Creates a [DoubleBuffer] with the specified [size], where each element is calculated by calling the specified
+         * Creates a [Float64Buffer] with the specified [size], where each element is calculated by calling the specified
          * [initializer] function.
          */
-        public inline fun double(size: Int, initializer: (Int) -> Double): DoubleBuffer =
-            DoubleBuffer(size, initializer)
+        public inline fun double(size: Int, initializer: (Int) -> Double): Float64Buffer =
+            Float64Buffer(size, initializer)
 
         /**
-         * Creates a [ShortBuffer] with the specified [size], where each element is calculated by calling the specified
+         * Creates a [Int16Buffer] with the specified [size], where each element is calculated by calling the specified
          * [initializer] function.
          */
-        public inline fun short(size: Int, initializer: (Int) -> Short): ShortBuffer =
-            ShortBuffer(size, initializer)
+        public inline fun short(size: Int, initializer: (Int) -> Short): Int16Buffer =
+            Int16Buffer(size, initializer)
 
         /**
-         * Creates a [IntBuffer] with the specified [size], where each element is calculated by calling the specified
+         * Creates a [Int32Buffer] with the specified [size], where each element is calculated by calling the specified
          * [initializer] function.
          */
-        public inline fun int(size: Int, initializer: (Int) -> Int): IntBuffer =
-            IntBuffer(size, initializer)
+        public inline fun int(size: Int, initializer: (Int) -> Int): Int32Buffer =
+            Int32Buffer(size, initializer)
 
         /**
-         * Creates a [LongBuffer] with the specified [size], where each element is calculated by calling the specified
+         * Creates a [Int64Buffer] with the specified [size], where each element is calculated by calling the specified
          * [initializer] function.
          */
-        public inline fun long(size: Int, initializer: (Int) -> Long): LongBuffer =
-            LongBuffer(size, initializer)
+        public inline fun long(size: Int, initializer: (Int) -> Long): Int64Buffer =
+            Int64Buffer(size, initializer)
 
 
         /**
-         * Creates a [FloatBuffer] with the specified [size], where each element is calculated by calling the specified
+         * Creates a [Float32Buffer] with the specified [size], where each element is calculated by calling the specified
          * [initializer] function.
          */
-        public inline fun float(size: Int, initializer: (Int) -> Float): FloatBuffer =
-            FloatBuffer(size, initializer)
-
-
-        /**
-         * Create a boxing mutable buffer of given type
-         */
-        public inline fun <T> boxing(size: Int, initializer: (Int) -> T): MutableBuffer<T> =
-            MutableListBuffer(MutableList(size, initializer))
-
-        /**
-         * Creates a [MutableBuffer] of given [type]. If the type is primitive, specialized buffers are used
-         * ([IntBuffer], [DoubleBuffer], etc.), [ListBuffer] is returned otherwise.
-         *
-         * The [size] is specified, and each element is calculated by calling the specified [initializer] function.
-         */
-        @Suppress("UNCHECKED_CAST")
-        public inline fun <T : Any> auto(type: KClass<out T>, size: Int, initializer: (Int) -> T): MutableBuffer<T> =
-            when (type) {
-                Double::class -> double(size) { initializer(it) as Double } as MutableBuffer<T>
-                Short::class -> short(size) { initializer(it) as Short } as MutableBuffer<T>
-                Int::class -> int(size) { initializer(it) as Int } as MutableBuffer<T>
-                Float::class -> float(size) { initializer(it) as Float } as MutableBuffer<T>
-                Long::class -> long(size) { initializer(it) as Long } as MutableBuffer<T>
-                else -> boxing(size, initializer)
-            }
-
-        /**
-         * Creates a [MutableBuffer] of given type [T]. If the type is primitive, specialized buffers are used
-         * ([IntBuffer], [DoubleBuffer], etc.), [ListBuffer] is returned otherwise.
-         *
-         * The [size] is specified, and each element is calculated by calling the specified [initializer] function.
-         */
-        @Suppress("UNCHECKED_CAST")
-        public inline fun <reified T : Any> auto(size: Int, initializer: (Int) -> T): MutableBuffer<T> =
-            auto(T::class, size, initializer)
+        public inline fun float(size: Int, initializer: (Int) -> Float): Float32Buffer =
+            Float32Buffer(size, initializer)
     }
 }
 
 
-public sealed interface PrimitiveBuffer<T>: MutableBuffer<T>
\ No newline at end of file
+/**
+ * Returns a shallow copy of the buffer.
+ */
+public fun <T> Buffer<T>.copy(bufferFactory: BufferFactory<T>): Buffer<T> = if (this is ArrayBuffer) {
+    ArrayBuffer(array.copyOf())
+} else {
+    bufferFactory(size, ::get)
+}
+
+/**
+ * Returns a mutable shallow copy of the buffer.
+ */
+public fun <T> Buffer<T>.mutableCopy(bufferFactory: MutableBufferFactory<T>): MutableBuffer<T> =
+    if (this is ArrayBuffer) {
+        ArrayBuffer(array.copyOf())
+    } else {
+        bufferFactory(size, ::get)
+    }
+
+
+/**
+ * Creates a [MutableBuffer] of given [type]. If the type is primitive, specialized buffers are used
+ * ([Int32Buffer], [Float64Buffer], etc.), [ListBuffer] is returned otherwise.
+ *
+ * The [size] is specified, and each element is calculated by calling the specified [initializer] function.
+ */
+@Suppress("UNCHECKED_CAST")
+public inline fun <T> MutableBuffer(
+    type: SafeType<T>,
+    size: Int,
+    initializer: (Int) -> T,
+): MutableBuffer<T> = when (type.kType) {
+    typeOf<Int8>() -> Int8Buffer(size) { initializer(it) as Int8 } as MutableBuffer<T>
+    typeOf<Int16>() -> MutableBuffer.short(size) { initializer(it) as Int16 } as MutableBuffer<T>
+    typeOf<Int32>() -> MutableBuffer.int(size) { initializer(it) as Int32 } as MutableBuffer<T>
+    typeOf<Int64>() -> MutableBuffer.long(size) { initializer(it) as Int64 } as MutableBuffer<T>
+    typeOf<Float>() -> MutableBuffer.float(size) { initializer(it) as Float } as MutableBuffer<T>
+    typeOf<Double>() -> MutableBuffer.double(size) { initializer(it) as Double } as MutableBuffer<T>
+    //TODO add unsigned types
+    else -> MutableListBuffer(MutableList(size, initializer))
+}
+
+/**
+ * Creates a [MutableBuffer] of given type [T]. If the type is primitive, specialized buffers are used
+ * ([Int32Buffer], [Float64Buffer], etc.), [ListBuffer] is returned otherwise.
+ *
+ * The [size] is specified, and each element is calculated by calling the specified [initializer] function.
+ */
+public inline fun <reified T> MutableBuffer(size: Int, initializer: (Int) -> T): MutableBuffer<T> =
+    MutableBuffer(safeTypeOf<T>(), size, initializer)
+
+
+public sealed interface PrimitiveBuffer<T> : MutableBuffer<T>
\ No newline at end of file
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferExtensions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferExtensions.kt
index 6a7b6d836..7c69669c8 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferExtensions.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferExtensions.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferPrimitiveAccess.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferPrimitiveAccess.kt
index 353892105..6035811b9 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferPrimitiveAccess.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferPrimitiveAccess.kt
@@ -1,3 +1,8 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
 package space.kscience.kmath.structures
 
 import space.kscience.kmath.UnstableKMathAPI
@@ -13,7 +18,7 @@ public fun Buffer<Double>.getDouble(index: Int): Double = if (this is BufferView
     } else {
         get(index)
     }
-} else if (this is DoubleBuffer) {
+} else if (this is Float64Buffer) {
     array[index]
 } else {
     get(index)
@@ -30,7 +35,7 @@ public fun Buffer<Int>.getInt(index: Int): Int = if (this is BufferView) {
     } else {
         get(index)
     }
-} else if (this is IntBuffer) {
+} else if (this is Int32Buffer) {
     array[index]
 } else {
     get(index)
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/types.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/types.kt
index 4ace17538..3d5f87abc 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/types.kt
+++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/types.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt
index 871119f48..eb679cec6 100644
--- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt
+++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,7 +8,7 @@
 package space.kscience.kmath.expressions
 
 import space.kscience.kmath.UnstableKMathAPI
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import kotlin.contracts.InvocationKind
 import kotlin.contracts.contract
 import kotlin.test.Test
@@ -18,10 +18,10 @@ import kotlin.test.assertFails
 internal inline fun diff(
     order: Int,
     vararg parameters: Pair<Symbol, Double>,
-    block: DSField<Double, DoubleField>.() -> Unit,
+    block: DSField<Double, Float64Field>.() -> Unit,
 ) {
     contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
-    DSField(DoubleField, order, mapOf(*parameters)).block()
+    DSField(Float64Field, order, mapOf(*parameters)).block()
 }
 
 internal class DSTest {
@@ -44,7 +44,7 @@ internal class DSTest {
 
     @Test
     fun dsExpressionTest() {
-        val f = DSFieldExpression(DoubleField) {
+        val f = DSFieldExpression(Float64Field) {
             val x by binding
             val y by binding
             x.pow(2) + 2 * x * y + y.pow(2) + 1
diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt
index def9f91a6..ca2e31d7d 100644
--- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt
+++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt
@@ -1,11 +1,11 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.expressions
 
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import kotlin.test.Test
 import kotlin.test.assertEquals
 import kotlin.test.assertFails
@@ -15,7 +15,7 @@ class ExpressionFieldTest {
 
     @Test
     fun testExpression() {
-        val expression = with(FunctionalExpressionField(DoubleField)) {
+        val expression = with(FunctionalExpressionField(Float64Field)) {
             val x by binding
             x * x + 2 * x + one
         }
@@ -31,7 +31,7 @@ class ExpressionFieldTest {
             return x * x + 2 * x + one
         }
 
-        val expression = FunctionalExpressionField(DoubleField).expression()
+        val expression = FunctionalExpressionField(Float64Field).expression()
         assertEquals(expression(x to 1.0), 4.0)
     }
 
@@ -42,7 +42,7 @@ class ExpressionFieldTest {
             x * x + 2 * x + one
         }
 
-        val expression = FunctionalExpressionField(DoubleField).expressionBuilder()
+        val expression = FunctionalExpressionField(Float64Field).expressionBuilder()
         assertEquals(expression(x to 1.0), 4.0)
     }
 }
diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt
index 83f00ce6c..b9ab5e62c 100644
--- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt
+++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,7 +8,7 @@ package space.kscience.kmath.expressions
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.expressions.Symbol.Companion.x
 import space.kscience.kmath.operations.BooleanAlgebra
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.invoke
 import kotlin.test.Test
 import kotlin.test.assertEquals
@@ -19,7 +19,7 @@ internal class InterpretTest {
     fun interpretation() {
         val expr = MstField {
             x * 2.0 + number(2.0) / x - 16.0
-        }.toExpression(DoubleField)
+        }.toExpression(Float64Field)
         assertEquals(-10.69, expr(x to 2.2), 0.02)
     }
 
diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt
index 1618296be..dcfb16042 100644
--- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt
+++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt
@@ -1,11 +1,11 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.expressions
 
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.bindSymbol
 import space.kscience.kmath.structures.Buffer
 import space.kscience.kmath.structures.asBuffer
@@ -21,19 +21,19 @@ internal class SimpleAutoDiffTest {
 
     fun dx(
         xBinding: Pair<Symbol, Double>,
-        body: SimpleAutoDiffField<Double, DoubleField>.(x: AutoDiffValue<Double>) -> AutoDiffValue<Double>,
-    ): DerivationResult<Double> = DoubleField.simpleAutoDiff(xBinding) { body(bindSymbol(xBinding.first)) }
+        body: SimpleAutoDiffField<Double, Float64Field>.(x: AutoDiffValue<Double>) -> AutoDiffValue<Double>,
+    ): DerivationResult<Double> = Float64Field.simpleAutoDiff(xBinding) { body(bindSymbol(xBinding.first)) }
 
     fun dxy(
         xBinding: Pair<Symbol, Double>,
         yBinding: Pair<Symbol, Double>,
-        body: SimpleAutoDiffField<Double, DoubleField>.(x: AutoDiffValue<Double>, y: AutoDiffValue<Double>) -> AutoDiffValue<Double>,
-    ): DerivationResult<Double> = DoubleField.simpleAutoDiff(xBinding, yBinding) {
+        body: SimpleAutoDiffField<Double, Float64Field>.(x: AutoDiffValue<Double>, y: AutoDiffValue<Double>) -> AutoDiffValue<Double>,
+    ): DerivationResult<Double> = Float64Field.simpleAutoDiff(xBinding, yBinding) {
         body(bindSymbol(xBinding.first), bindSymbol(yBinding.first))
     }
 
-    fun diff(block: SimpleAutoDiffField<Double, DoubleField>.() -> AutoDiffValue<Double>): SimpleAutoDiffExpression<Double, DoubleField> {
-        return SimpleAutoDiffExpression(DoubleField, block)
+    fun diff(block: SimpleAutoDiffField<Double, Float64Field>.() -> AutoDiffValue<Double>): SimpleAutoDiffExpression<Double, Float64Field> {
+        return SimpleAutoDiffExpression(Float64Field, block)
     }
 
     val x by symbol
@@ -42,7 +42,7 @@ internal class SimpleAutoDiffTest {
 
     @Test
     fun testPlusX2() {
-        val y = DoubleField.simpleAutoDiff(x to 3.0) {
+        val y = Float64Field.simpleAutoDiff(x to 3.0) {
             // diff w.r.t this x at 3
             val x = bindSymbol(x)
             x + x
@@ -65,7 +65,7 @@ internal class SimpleAutoDiffTest {
     @Test
     fun testPlus() {
         // two variables
-        val z = DoubleField.simpleAutoDiff(x to 2.0, y to 3.0) {
+        val z = Float64Field.simpleAutoDiff(x to 2.0, y to 3.0) {
             val x = bindSymbol(x)
             val y = bindSymbol(y)
             x + y
@@ -78,7 +78,7 @@ internal class SimpleAutoDiffTest {
     @Test
     fun testMinus() {
         // two variables
-        val z = DoubleField.simpleAutoDiff(x to 7.0, y to 3.0) {
+        val z = Float64Field.simpleAutoDiff(x to 7.0, y to 3.0) {
             val x = bindSymbol(x)
             val y = bindSymbol(y)
 
diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt
index 4d05f9043..037fdf3e5 100644
--- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt
+++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -10,7 +10,6 @@ import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.nd.StructureND
 import space.kscience.kmath.operations.algebra
 import kotlin.test.Test
-import kotlin.test.assertEquals
 import kotlin.test.assertTrue
 
 @OptIn(PerformancePitfall::class)
@@ -22,29 +21,29 @@ fun <T : Any> assertMatrixEquals(expected: StructureND<T>, actual: StructureND<T
 class DoubleLUSolverTest {
 
     @Test
-    fun testInvertOne() = Double.algebra.linearSpace.run{
+    fun testInvertOne() = Double.algebra.linearSpace.run {
         val matrix = one(2, 2)
         val inverted = lupSolver().inverse(matrix)
         assertMatrixEquals(matrix, inverted)
     }
 
     @Test
-    fun testDecomposition() = Double.algebra.linearSpace.run {
+    fun testDecomposition() = with(Double.algebra.linearSpace) {
         val matrix = matrix(2, 2)(
             3.0, 1.0,
             2.0, 3.0
         )
 
-        val lup = lup(matrix)
+        val lup = elementAlgebra.lup(matrix)
 
         //Check determinant
-        assertEquals(7.0, lup.determinant)
+//        assertEquals(7.0, lup.determinant)
 
-        assertMatrixEquals(lup.p dot matrix, lup.l dot lup.u)
+        assertMatrixEquals(lup.pivotMatrix(this) dot matrix, lup.l dot lup.u)
     }
 
     @Test
-    fun testInvert()  = Double.algebra.linearSpace.run{
+    fun testInvert() = Double.algebra.linearSpace.run {
         val matrix = matrix(2, 2)(
             3.0, 1.0,
             1.0, 3.0
diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt
index 531aee259..30b8aaffb 100644
--- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt
+++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,7 +8,7 @@ package space.kscience.kmath.linear
 import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.nd.StructureND
-import space.kscience.kmath.nd.as2D
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.algebra
 import kotlin.test.Test
 import kotlin.test.assertEquals
@@ -22,7 +22,7 @@ class MatrixTest {
     @Test
     fun testTranspose() = Double.algebra.linearSpace.run {
         val matrix = one(3, 3)
-        val transposed = matrix.transpose()
+        val transposed = matrix.transposed()
         assertTrue { StructureND.contentEquals(matrix, transposed) }
     }
 
@@ -50,7 +50,7 @@ class MatrixTest {
         infix fun Matrix<Double>.pow(power: Int): Matrix<Double> {
             var res = this
             repeat(power - 1) {
-                res =  res dot this@pow
+                res = res dot this@pow
             }
             return res
         }
@@ -59,9 +59,9 @@ class MatrixTest {
     }
 
     @Test
-    fun test2DDot() = Double.algebra.linearSpace.run {
-        val firstMatrix = StructureND.auto(2, 3) { (i, j) -> (i + j).toDouble() }.as2D()
-        val secondMatrix = StructureND.auto(3, 2) { (i, j) -> (i + j).toDouble() }.as2D()
+    fun test2DDot() = Float64Field.linearSpace {
+        val firstMatrix = buildMatrix(2, 3) { i, j -> (i + j).toDouble() }
+        val secondMatrix = buildMatrix(3, 2) { i, j -> (i + j).toDouble() }
 
 //            val firstMatrix = produce(2, 3) { i, j -> (i + j).toDouble() }
 //            val secondMatrix = produce(3, 2) { i, j -> (i + j).toDouble() }
@@ -71,6 +71,5 @@ class MatrixTest {
         assertEquals(8.0, result[0, 1])
         assertEquals(8.0, result[1, 0])
         assertEquals(14.0, result[1, 1])
-
     }
 }
diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt
index 811f2e87f..9cedb8bb3 100644
--- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt
+++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt
index dd97df1e8..f17f32738 100644
--- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt
+++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,7 +7,7 @@ package space.kscience.kmath.misc
 
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.misc.PermSortTest.Platform.*
-import space.kscience.kmath.structures.IntBuffer
+import space.kscience.kmath.structures.Int32Buffer
 import space.kscience.kmath.structures.asBuffer
 import kotlin.random.Random
 import kotlin.test.Test
@@ -29,7 +29,7 @@ class PermSortTest {
      */
     @Test
     fun testOnEmptyBuffer() {
-        val emptyBuffer = IntBuffer(0) {it}
+        val emptyBuffer = Int32Buffer(0) { it }
         var permutations = emptyBuffer.indicesSorted()
         assertTrue(permutations.isEmpty(), "permutation on an empty buffer should return an empty result")
         permutations = emptyBuffer.indicesSortedDescending()
@@ -67,10 +67,14 @@ class PermSortTest {
         assertContentEquals(expected, permutations.map { platforms[it] }, "PermSort using custom ascending comparator")
 
         permutations = platforms.indicesSortedWith(compareByDescending { it.name.length })
-        assertContentEquals(expected.reversed(), permutations.map { platforms[it] }, "PermSort using custom descending comparator")
+        assertContentEquals(
+            expected.reversed(),
+            permutations.map { platforms[it] },
+            "PermSort using custom descending comparator"
+        )
     }
 
-    private fun testPermutation(bufferSize: Int) {   
+    private fun testPermutation(bufferSize: Int) {
 
         val seed = Random.nextLong()
         println("Test randomization seed: $seed")
@@ -82,23 +86,23 @@ class PermSortTest {
         // Ensure no doublon is present in indices
         assertEquals(indices.toSet().size, indices.size)
 
-        for (i in 0 until (bufferSize-1)) {
+        for (i in 0 until (bufferSize - 1)) {
             val current = buffer[indices[i]]
-            val next = buffer[indices[i+1]]
+            val next = buffer[indices[i + 1]]
             assertTrue(current <= next, "Permutation indices not properly sorted")
         }
 
         val descIndices = buffer.indicesSortedDescending()
-        assertEquals(bufferSize, descIndices.size) 
+        assertEquals(bufferSize, descIndices.size)
         // Ensure no doublon is present in indices
         assertEquals(descIndices.toSet().size, descIndices.size)
 
-        for (i in 0 until (bufferSize-1)) {
+        for (i in 0 until (bufferSize - 1)) {
             val current = buffer[descIndices[i]]
-            val next = buffer[descIndices[i+1]]
+            val next = buffer[descIndices[i + 1]]
             assertTrue(current >= next, "Permutation indices not properly sorted in descending order")
         }
     }
 
-    private fun Random.buffer(size : Int) = IntBuffer(size) { nextInt() }
+    private fun Random.buffer(size: Int) = Int32Buffer(size) { nextInt() }
 }
diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/NdOperationsTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/NdOperationsTest.kt
index e909a2aea..d3c1dbc3b 100644
--- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/NdOperationsTest.kt
+++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/NdOperationsTest.kt
@@ -1,24 +1,24 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.nd
 
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import kotlin.test.Test
 import kotlin.test.assertEquals
 
 class NdOperationsTest {
     @Test
     fun roll() {
-        val structure = DoubleField.ndAlgebra.structureND(5, 5) { index ->
+        val structure = Float64Field.ndAlgebra.structureND(5, 5) { index ->
             index.sumOf { it.toDouble() }
         }
 
         println(StructureND.toString(structure))
 
-        val rolled = structure.roll(0,-1)
+        val rolled = structure.roll(0, -1)
 
         println(StructureND.toString(rolled))
 
diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/StridesTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/StridesTest.kt
index e6335f652..224968e14 100644
--- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/StridesTest.kt
+++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/StridesTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -12,10 +12,10 @@ class StridesTest {
     fun checkRowBasedStrides() {
         val strides = RowStrides(ShapeND(3, 3))
         var counter = 0
-        for(i in 0..2){
-            for(j in 0..2){
+        for (i in 0..2) {
+            for (j in 0..2) {
 //                print(strides.offset(intArrayOf(i,j)).toString() + "\t")
-                require(strides.offset(intArrayOf(i,j)) == counter)
+                require(strides.offset(intArrayOf(i, j)) == counter)
                 counter++
             }
             println()
@@ -26,10 +26,10 @@ class StridesTest {
     fun checkColumnBasedStrides() {
         val strides = ColumnStrides(ShapeND(3, 3))
         var counter = 0
-        for(i in 0..2){
-            for(j in 0..2){
+        for (i in 0..2) {
+            for (j in 0..2) {
 //                print(strides.offset(intArrayOf(i,j)).toString() + "\t")
-                require(strides.offset(intArrayOf(j,i)) == counter)
+                require(strides.offset(intArrayOf(j, i)) == counter)
                 counter++
             }
             println()
diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt
index 06a9ab439..0bbb92151 100644
--- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt
+++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt
index 786c68c70..69bccacdd 100644
--- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt
+++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt
index 36f00dc75..f9b5dca2a 100644
--- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt
+++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt
index 8a6116605..1f47dc2c1 100644
--- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt
+++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt
index 688daa7fe..51783df13 100644
--- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt
+++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -11,16 +11,16 @@ import kotlin.test.assertEquals
 
 internal class DoubleFieldTest {
     @Test
-    fun verify() = FieldVerifier(DoubleField, 42.0, 66.0, 2.0, 5).verify()
+    fun verify() = FieldVerifier(Float64Field, 42.0, 66.0, 2.0, 5).verify()
 
     @Test
     fun testSqrt() {
-        val sqrt = DoubleField { sqrt(25 * one) }
+        val sqrt = Float64Field { sqrt(25 * one) }
         assertEquals(5.0, sqrt)
     }
 
     @Test
-    fun testPow() = DoubleField {
+    fun testPow() = Float64Field {
         val num = 5 * one
         assertEquals(5.0, power(num, 1), 0.01)
         assertEquals(25.0, power(num, 2), 0.01)
diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/BufferExpandedTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/BufferExpandedTest.kt
index 04671e040..37cc4a533 100644
--- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/BufferExpandedTest.kt
+++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/BufferExpandedTest.kt
@@ -1,3 +1,8 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
 package space.kscience.kmath.structures
 
 import kotlin.test.Test
@@ -8,7 +13,7 @@ internal class BufferExpandedTest {
     private val buffer = (0..100).toList().asBuffer()
 
     @Test
-    fun shrink(){
+    fun shrink() {
         val view = buffer.slice(20..30)
         assertEquals(20, view[0])
         assertEquals(30, view[10])
@@ -16,10 +21,10 @@ internal class BufferExpandedTest {
     }
 
     @Test
-    fun expandNegative(){
-        val view: BufferView<Int> = buffer.expand(-20..113,0)
-        assertEquals(0,view[4])
-        assertEquals(0,view[123])
+    fun expandNegative() {
+        val view: BufferView<Int> = buffer.expand(-20..113, 0)
+        assertEquals(0, view[4])
+        assertEquals(0, view[123])
         assertEquals(100, view[120])
         assertFails { view[-2] }
         assertFails { view[134] }
diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt
index 566145621..0fc9cb9e3 100644
--- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt
+++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,7 +8,7 @@ package space.kscience.kmath.structures
 import space.kscience.kmath.nd.get
 import space.kscience.kmath.nd.ndAlgebra
 import space.kscience.kmath.nd.structureND
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.invoke
 import space.kscience.kmath.testutils.FieldVerifier
 import kotlin.test.Test
@@ -17,12 +17,12 @@ import kotlin.test.assertEquals
 internal class NDFieldTest {
     @Test
     fun verify() {
-        (DoubleField.ndAlgebra(12, 32)) { FieldVerifier(this, one + 3, one - 23, one * 12, 6.66) }
+        (Float64Field.ndAlgebra(12, 32)) { FieldVerifier(this, one + 3, one - 23, one * 12, 6.66) }
     }
 
     @Test
     fun testStrides() {
-        val ndArray = DoubleField.ndAlgebra.structureND(10, 10) { (it[0] + it[1]).toDouble() }
+        val ndArray = Float64Field.ndAlgebra.structureND(10, 10) { (it[0] + it[1]).toDouble() }
         assertEquals(ndArray[5, 5], 10.0)
     }
 }
diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt
index 993fb089f..2f10af972 100644
--- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt
+++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -11,7 +11,7 @@ import space.kscience.kmath.nd.StructureND
 import space.kscience.kmath.nd.get
 import space.kscience.kmath.nd.ndAlgebra
 import space.kscience.kmath.nd.structureND
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.Norm
 import space.kscience.kmath.operations.algebra
 import space.kscience.kmath.operations.invoke
@@ -25,7 +25,7 @@ import kotlin.test.assertEquals
 @OptIn(PerformancePitfall::class)
 @Suppress("UNUSED_VARIABLE")
 class NumberNDFieldTest {
-    val algebra = DoubleField.ndAlgebra
+    val algebra = Float64Field.ndAlgebra
     val array1 = algebra.structureND(3, 3) { (i, j) -> (i + j).toDouble() }
     val array2 = algebra.structureND(3, 3) { (i, j) -> (i - j).toDouble() }
 
@@ -94,7 +94,7 @@ class NumberNDFieldTest {
     @Test
     fun testInternalContext() {
         algebra {
-            (DoubleField.ndAlgebra(array1.shape)) { with(L2Norm) { 1 + norm(array1) + exp(array2) } }
+            (Float64Field.ndAlgebra(array1.shape)) { with(L2Norm) { 1 + norm(array1) + exp(array2) } }
         }
     }
 }
diff --git a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt
index e52ea9298..e0875993f 100644
--- a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt
+++ b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt
index 3103f5168..da697bd77 100644
--- a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt
+++ b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/linear/Float64ParallelLinearSpace.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/linear/Float64ParallelLinearSpace.kt
new file mode 100644
index 000000000..1fb5625b3
--- /dev/null
+++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/linear/Float64ParallelLinearSpace.kt
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.linear
+
+import space.kscience.kmath.PerformancePitfall
+import space.kscience.kmath.nd.*
+import space.kscience.kmath.operations.Float64BufferOps
+import space.kscience.kmath.operations.Float64Field
+import space.kscience.kmath.operations.invoke
+import space.kscience.kmath.structures.Buffer
+import space.kscience.kmath.structures.Float64Buffer
+import space.kscience.kmath.structures.asBuffer
+import java.util.stream.IntStream
+
+
+public object Float64ParallelLinearSpace : LinearSpace<Double, Float64Field> {
+
+    override val elementAlgebra: Float64Field = Float64Field
+
+
+    override fun buildMatrix(
+        rows: Int,
+        columns: Int,
+        initializer: Float64Field.(i: Int, j: Int) -> Double,
+    ): Matrix<Double> {
+        val shape = ShapeND(rows, columns)
+        val indexer = BufferAlgebraND.defaultIndexerBuilder(shape)
+
+        val buffer = IntStream.range(0, indexer.linearSize).parallel().mapToDouble { offset ->
+            val (i, j) = indexer.index(offset)
+            elementAlgebra.initializer(i, j)
+        }.toArray().asBuffer()
+
+        return MutableBufferND(
+            indexer,
+            buffer
+        ).as2D()
+    }
+
+    override fun buildVector(size: Int, initializer: Float64Field.(Int) -> Double): Float64Buffer =
+        IntStream.range(0, size).parallel().mapToDouble { Float64Field.initializer(it) }.toArray().asBuffer()
+
+    override fun Matrix<Double>.unaryMinus(): Matrix<Double> = Floa64FieldOpsND {
+        asND().map { -it }.as2D()
+    }
+
+    override fun Matrix<Double>.plus(other: Matrix<Double>): Matrix<Double> = Floa64FieldOpsND {
+        require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::plus. Expected $shape but found ${other.shape}" }
+        asND().plus(other.asND()).as2D()
+    }
+
+    override fun Matrix<Double>.minus(other: Matrix<Double>): Matrix<Double> = Floa64FieldOpsND {
+        require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::minus. Expected $shape but found ${other.shape}" }
+        asND().minus(other.asND()).as2D()
+    }
+
+    // Create a continuous in-memory representation of this vector for better memory layout handling
+    private fun Buffer<Double>.linearize() = if (this is Float64Buffer) {
+        this.array
+    } else {
+        DoubleArray(size) { get(it) }
+    }
+
+    @OptIn(PerformancePitfall::class)
+    override fun Matrix<Double>.dot(other: Matrix<Double>): Matrix<Double> {
+        require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" }
+        val rows = this@dot.rows.map { it.linearize() }
+        val columns = other.columns.map { it.linearize() }
+        val indices = 0 until this.colNum
+        return buildMatrix(rowNum, other.colNum) { i, j ->
+            val r = rows[i]
+            val c = columns[j]
+            var res = 0.0
+            for (l in indices) {
+                res += r[l] * c[l]
+            }
+            res
+        }
+    }
+
+    @OptIn(PerformancePitfall::class)
+    override fun Matrix<Double>.dot(vector: Point<Double>): Float64Buffer {
+        require(colNum == vector.size) { "Matrix dot vector operation dimension mismatch: ($rowNum, $colNum) x (${vector.size})" }
+        val rows = this@dot.rows.map { it.linearize() }
+        val indices = 0 until this.colNum
+        return Float64Buffer(rowNum) { i ->
+            val r = rows[i]
+            var res = 0.0
+            for (j in indices) {
+                res += r[j] * vector[j]
+            }
+            res
+        }
+
+    }
+
+    override fun Matrix<Double>.times(value: Double): Matrix<Double> = Floa64FieldOpsND {
+        asND().map { it * value }.as2D()
+    }
+
+    public override fun Point<Double>.plus(other: Point<Double>): Float64Buffer = Float64BufferOps.run {
+        this@plus + other
+    }
+
+    public override fun Point<Double>.minus(other: Point<Double>): Float64Buffer = Float64BufferOps.run {
+        this@minus - other
+    }
+
+    public override fun Point<Double>.times(value: Double): Float64Buffer = Float64BufferOps.run {
+        scale(this@times, value)
+    }
+
+    public operator fun Point<Double>.div(value: Double): Float64Buffer = Float64BufferOps.run {
+        scale(this@div, 1.0 / value)
+    }
+
+    public override fun Double.times(v: Point<Double>): Float64Buffer = v * this
+
+
+}
+
+public val Float64LinearSpace.parallel: Float64ParallelLinearSpace get() = Float64ParallelLinearSpace
diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt
index 3780ea1ae..222e1bca1 100644
--- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt
+++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt
index 584748bd7..d1dbca00f 100644
--- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt
+++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt
@@ -1,10 +1,11 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.operations
 
+import space.kscience.kmath.structures.MutableBufferFactory
 import java.math.BigDecimal
 import java.math.BigInteger
 import java.math.MathContext
@@ -13,6 +14,8 @@ import java.math.MathContext
  * A field over [BigInteger].
  */
 public object JBigIntegerField : Ring<BigInteger>, NumericAlgebra<BigInteger> {
+
+    override val bufferFactory: MutableBufferFactory<BigInteger> = MutableBufferFactory()
     override val zero: BigInteger get() = BigInteger.ZERO
 
     override val one: BigInteger get() = BigInteger.ONE
@@ -33,6 +36,7 @@ public object JBigIntegerField : Ring<BigInteger>, NumericAlgebra<BigInteger> {
 public abstract class JBigDecimalFieldBase internal constructor(
     private val mathContext: MathContext = MathContext.DECIMAL64,
 ) : Field<BigDecimal>, PowerOperations<BigDecimal>, NumericAlgebra<BigDecimal>, ScaleOperations<BigDecimal> {
+    override val bufferFactory: MutableBufferFactory<BigDecimal> = MutableBufferFactory()
     override val zero: BigDecimal
         get() = BigDecimal.ZERO
 
diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt
index 9868daddf..e0b1cbe83 100644
--- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt
+++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,4 +8,5 @@ package space.kscience.kmath.operations
 /**
  * Check if number is an integer
  */
-public actual fun Number.isInteger(): Boolean = (this is Int) || (this is Long) || (this is Short) || (this.toDouble() % 1 == 0.0)
\ No newline at end of file
+public actual fun Number.isInteger(): Boolean =
+    (this is Int) || (this is Long) || (this is Short) || (this.toDouble() % 1 == 0.0)
\ No newline at end of file
diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/structures/parallelMutableBuffer.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/structures/parallelMutableBuffer.kt
new file mode 100644
index 000000000..d19f50dba
--- /dev/null
+++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/structures/parallelMutableBuffer.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.structures
+
+import space.kscience.attributes.SafeType
+import java.util.stream.Collectors
+import java.util.stream.IntStream
+import kotlin.reflect.typeOf
+
+/**
+ * A Java stream-based parallel version of [MutableBuffer].
+ * There is no parallelization for [Int8], [Int16] and [Float32] types.
+ * They are processed sequentially.
+ */
+@Suppress("UNCHECKED_CAST")
+public fun <T> MutableBuffer.Companion.parallel(
+    type: SafeType<T>,
+    size: Int,
+    initializer: (Int) -> T,
+): MutableBuffer<T> = when (type.kType) {
+    typeOf<Int8>() -> Int8Buffer(size) { initializer(it) as Int8 } as MutableBuffer<T>
+    typeOf<Int16>() -> Int16Buffer(size) { initializer(it) as Int16 } as MutableBuffer<T>
+    typeOf<Int32>() -> IntStream.range(0, size).parallel().map { initializer(it) as Int32 }.toArray()
+        .asBuffer() as MutableBuffer<T>
+
+    typeOf<Int64>() -> IntStream.range(0, size).parallel().mapToLong { initializer(it) as Int64 }.toArray()
+        .asBuffer() as MutableBuffer<T>
+
+    typeOf<Float>() -> Float32Buffer(size) { initializer(it) as Float } as MutableBuffer<T>
+    typeOf<Double>() -> IntStream.range(0, size).parallel().mapToDouble { initializer(it) as Float64 }.toArray()
+        .asBuffer() as MutableBuffer<T>
+    //TODO add unsigned types
+    else -> IntStream.range(0, size).parallel().mapToObj { initializer(it) }.collect(Collectors.toList<T>())
+        .asMutableBuffer()
+}
+
+public class ParallelBufferFactory<T>(override val type: SafeType<T>) : MutableBufferFactory<T> {
+    override fun invoke(size: Int, builder: (Int) -> T): MutableBuffer<T> {
+        TODO("Not yet implemented")
+    }
+
+}
+
+/**
+ * A Java stream-based parallel alternative to [MutableBufferFactory].
+ * See [MutableBuffer.Companion.parallel] for details.
+ */
+public fun <T> MutableBufferFactory.Companion.parallel(
+    type: SafeType<T>,
+): MutableBufferFactory<T> = object : MutableBufferFactory<T> {
+
+    override val type: SafeType<T> = type
+
+    override fun invoke(size: Int, builder: (Int) -> T): MutableBuffer<T> = MutableBuffer.parallel(type, size, builder)
+
+}
\ No newline at end of file
diff --git a/kmath-core/src/jvmTest/kotlin/space/kscience/kmath/linear/ParallelMatrixTest.kt b/kmath-core/src/jvmTest/kotlin/space/kscience/kmath/linear/ParallelMatrixTest.kt
new file mode 100644
index 000000000..2abc36c8e
--- /dev/null
+++ b/kmath-core/src/jvmTest/kotlin/space/kscience/kmath/linear/ParallelMatrixTest.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.linear
+
+import space.kscience.kmath.PerformancePitfall
+import space.kscience.kmath.UnstableKMathAPI
+import space.kscience.kmath.nd.StructureND
+import space.kscience.kmath.operations.Float64Field
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
+
+@UnstableKMathAPI
+@OptIn(PerformancePitfall::class)
+@Suppress("UNUSED_VARIABLE")
+class ParallelMatrixTest {
+
+    @Test
+    fun testTranspose() = Float64Field.linearSpace.parallel {
+        val matrix = one(3, 3)
+        val transposed = matrix.transposed()
+        assertTrue { StructureND.contentEquals(matrix, transposed) }
+    }
+
+    @Test
+    fun testBuilder() = Float64Field.linearSpace.parallel {
+        val matrix = matrix(2, 3)(
+            1.0, 0.0, 0.0,
+            0.0, 1.0, 2.0
+        )
+
+        assertEquals(2.0, matrix[1, 2])
+    }
+
+    @Test
+    fun testMatrixExtension() = Float64Field.linearSpace.parallel {
+        val transitionMatrix: Matrix<Double> = VirtualMatrix(6, 6) { row, col ->
+            when {
+                col == 0 -> .50
+                row + 1 == col -> .50
+                row == 5 && col == 5 -> 1.0
+                else -> 0.0
+            }
+        }
+
+        infix fun Matrix<Double>.pow(power: Int): Matrix<Double> {
+            var res = this
+            repeat(power - 1) {
+                res = res dot this@pow
+            }
+            return res
+        }
+
+        val toTenthPower = transitionMatrix pow 10
+    }
+
+    @Test
+    fun test2DDot() = Float64Field.linearSpace.parallel {
+        val firstMatrix = buildMatrix(2, 3) { i, j -> (i + j).toDouble() }
+        val secondMatrix = buildMatrix(3, 2) { i, j -> (i + j).toDouble() }
+
+//            val firstMatrix = produce(2, 3) { i, j -> (i + j).toDouble() }
+//            val secondMatrix = produce(3, 2) { i, j -> (i + j).toDouble() }
+        val result = firstMatrix dot secondMatrix
+        assertEquals(2, result.rowNum)
+        assertEquals(2, result.colNum)
+        assertEquals(8.0, result[0, 1])
+        assertEquals(8.0, result[1, 0])
+        assertEquals(14.0, result[1, 1])
+    }
+}
diff --git a/kmath-core/src/jvmTest/kotlin/space/kscience/kmath/misc/JBigTest.kt b/kmath-core/src/jvmTest/kotlin/space/kscience/kmath/misc/JBigTest.kt
index f7f8027e6..f27257a4c 100644
--- a/kmath-core/src/jvmTest/kotlin/space/kscience/kmath/misc/JBigTest.kt
+++ b/kmath-core/src/jvmTest/kotlin/space/kscience/kmath/misc/JBigTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt
index e52ea9298..e0875993f 100644
--- a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt
+++ b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt
index 9868daddf..e0b1cbe83 100644
--- a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt
+++ b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,4 +8,5 @@ package space.kscience.kmath.operations
 /**
  * Check if number is an integer
  */
-public actual fun Number.isInteger(): Boolean = (this is Int) || (this is Long) || (this is Short) || (this.toDouble() % 1 == 0.0)
\ No newline at end of file
+public actual fun Number.isInteger(): Boolean =
+    (this is Int) || (this is Long) || (this is Short) || (this.toDouble() % 1 == 0.0)
\ No newline at end of file
diff --git a/kmath-core/src/wasmMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/wasmJsMain/kotlin/space/kscience/kmath/misc/numbers.kt
similarity index 87%
rename from kmath-core/src/wasmMain/kotlin/space/kscience/kmath/misc/numbers.kt
rename to kmath-core/src/wasmJsMain/kotlin/space/kscience/kmath/misc/numbers.kt
index e320f350e..e0875993f 100644
--- a/kmath-core/src/wasmMain/kotlin/space/kscience/kmath/misc/numbers.kt
+++ b/kmath-core/src/wasmJsMain/kotlin/space/kscience/kmath/misc/numbers.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2023 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-core/src/wasmMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/wasmJsMain/kotlin/space/kscience/kmath/operations/isInteger.kt
similarity index 84%
rename from kmath-core/src/wasmMain/kotlin/space/kscience/kmath/operations/isInteger.kt
rename to kmath-core/src/wasmJsMain/kotlin/space/kscience/kmath/operations/isInteger.kt
index 11c82bf9e..9f68527f7 100644
--- a/kmath-core/src/wasmMain/kotlin/space/kscience/kmath/operations/isInteger.kt
+++ b/kmath-core/src/wasmJsMain/kotlin/space/kscience/kmath/operations/isInteger.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2023 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-coroutines/README.md b/kmath-coroutines/README.md
index 21831e514..75ee7e5dc 100644
--- a/kmath-coroutines/README.md
+++ b/kmath-coroutines/README.md
@@ -6,19 +6,8 @@
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-coroutines:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-coroutines:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-coroutines:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -27,6 +16,6 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-coroutines:0.4.0-dev-1")
+    implementation("space.kscience:kmath-coroutines:0.4.0")
 }
 ```
diff --git a/kmath-coroutines/build.gradle.kts b/kmath-coroutines/build.gradle.kts
index 1e901ca98..0cb36e10a 100644
--- a/kmath-coroutines/build.gradle.kts
+++ b/kmath-coroutines/build.gradle.kts
@@ -6,10 +6,10 @@ kscience {
     jvm()
     js()
     native()
+    wasm()
 
     dependencies {
-        api(project(":kmath-core"))
-        api(project(":kmath-complex"))
+        api(projects.kmathCore)
         api(spclibs.kotlinx.coroutines.core)
     }
 }
diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt
index 2e9a15eed..f843e8af8 100644
--- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt
+++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -43,7 +43,7 @@ public interface BlockingBufferChain<out T> : BlockingChain<T>, BufferChain<T> {
 public suspend inline fun <reified T : Any> Chain<T>.nextBuffer(size: Int): Buffer<T> = if (this is BufferChain) {
     nextBuffer(size)
 } else {
-    Buffer.auto(size) { next() }
+    Buffer(size) { next() }
 }
 
 public inline fun <reified T : Any> BlockingChain<T>.nextBufferBlocking(
@@ -51,5 +51,5 @@ public inline fun <reified T : Any> BlockingChain<T>.nextBufferBlocking(
 ): Buffer<T> = if (this is BlockingBufferChain) {
     nextBufferBlocking(size)
 } else {
-    Buffer.auto(size) { nextBlocking() }
+    Buffer(size) { nextBlocking() }
 }
\ No newline at end of file
diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt
index 797d2db4a..b3e1b59b7 100644
--- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt
+++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt
@@ -1,11 +1,11 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.chains
 
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 
 /**
  * Chunked, specialized chain for double values, which supports blocking [nextBlocking] operation
@@ -15,7 +15,7 @@ public interface BlockingDoubleChain : BlockingBufferChain<Double> {
     /**
      * Returns an [DoubleArray] chunk of [size] values of [next].
      */
-    override fun nextBufferBlocking(size: Int): DoubleBuffer
+    override fun nextBufferBlocking(size: Int): Float64Buffer
 
     override suspend fun fork(): BlockingDoubleChain
 
@@ -23,9 +23,9 @@ public interface BlockingDoubleChain : BlockingBufferChain<Double> {
 }
 
 public fun BlockingDoubleChain.map(transform: (Double) -> Double): BlockingDoubleChain = object : BlockingDoubleChain {
-    override fun nextBufferBlocking(size: Int): DoubleBuffer {
+    override fun nextBufferBlocking(size: Int): Float64Buffer {
         val block = this@map.nextBufferBlocking(size)
-        return DoubleBuffer(size) { transform(block[it]) }
+        return Float64Buffer(size) { transform(block[it]) }
     }
 
     override suspend fun fork(): BlockingDoubleChain = this@map.fork().map(transform)
diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt
index a481156f2..82a6d131e 100644
--- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt
+++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt
@@ -1,17 +1,17 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.chains
 
-import space.kscience.kmath.structures.IntBuffer
+import space.kscience.kmath.structures.Int32Buffer
 
 /**
  * Performance optimized chain for integer values
  */
 public interface BlockingIntChain : BlockingBufferChain<Int> {
-    override fun nextBufferBlocking(size: Int): IntBuffer
+    override fun nextBufferBlocking(size: Int): Int32Buffer
 
     override suspend fun fork(): BlockingIntChain
 }
\ No newline at end of file
diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt
index 977346e68..0158c6752 100644
--- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt
+++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt
index 77d4203c5..52114752c 100644
--- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt
+++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt
index 48be93b87..8183d2d15 100644
--- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt
+++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt
index ccd329064..12665c8a5 100644
--- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt
+++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,15 +7,17 @@
 
 package space.kscience.kmath.streaming
 
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.FlowPreview
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.asFlow
 import kotlinx.coroutines.flow.flatMapConcat
 import kotlinx.coroutines.flow.flow
 import space.kscience.kmath.chains.BlockingDoubleChain
+import space.kscience.kmath.operations.Group
 import space.kscience.kmath.structures.Buffer
 import space.kscience.kmath.structures.BufferFactory
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 
 /**
  * Create a [Flow] from buffer
@@ -25,6 +27,7 @@ public fun <T> Buffer<T>.asFlow(): Flow<T> = iterator().asFlow()
 /**
  * Flat map a [Flow] of [Buffer] into continuous [Flow] of elements
  */
+@OptIn(ExperimentalCoroutinesApi::class)
 public fun <T> Flow<Buffer<T>>.spread(): Flow<T> = flatMapConcat { it.asFlow() }
 
 /**
@@ -53,7 +56,7 @@ public fun <T> Flow<T>.chunked(bufferSize: Int, bufferFactory: BufferFactory<T>)
 /**
  * Specialized flow chunker for real buffer
  */
-public fun Flow<Double>.chunked(bufferSize: Int): Flow<DoubleBuffer> = flow {
+public fun Flow<Double>.chunked(bufferSize: Int): Flow<Float64Buffer> = flow {
     require(bufferSize > 0) { "Resulting chunk size must be more than zero" }
 
     if (this@chunked is BlockingDoubleChain) {
@@ -68,13 +71,13 @@ public fun Flow<Double>.chunked(bufferSize: Int): Flow<DoubleBuffer> = flow {
             counter++
 
             if (counter == bufferSize) {
-                val buffer = DoubleBuffer(array)
+                val buffer = Float64Buffer(array)
                 emit(buffer)
                 counter = 0
             }
         }
 
-        if (counter > 0) emit(DoubleBuffer(counter) { array[it] })
+        if (counter > 0) emit(Float64Buffer(counter) { array[it] })
     }
 }
 
@@ -82,9 +85,9 @@ public fun Flow<Double>.chunked(bufferSize: Int): Flow<DoubleBuffer> = flow {
  * Map a flow to a moving window buffer. The window step is one.
  * 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, algebra: Group<T>): Flow<Buffer<T>> = flow {
     require(window > 1) { "Window size must be more than one" }
-    val ringBuffer = RingBuffer.boxing<T>(window)
+    val ringBuffer = RingBuffer(window, algebra)
 
     this@windowed.collect { element ->
         ringBuffer.push(element)
diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt
index 2ac8c1eb4..ce7f07860 100644
--- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt
+++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,31 +7,34 @@ package space.kscience.kmath.streaming
 
 import kotlinx.coroutines.sync.Mutex
 import kotlinx.coroutines.sync.withLock
-import space.kscience.kmath.structures.Buffer
-import space.kscience.kmath.structures.MutableBuffer
-import space.kscience.kmath.structures.VirtualBuffer
+import space.kscience.kmath.operations.Group
+import space.kscience.kmath.structures.*
 
 /**
  * Thread-safe ring buffer
  */
-@Suppress("UNCHECKED_CAST")
 public class RingBuffer<T>(
-    private val buffer: MutableBuffer<T?>,
+    private val buffer: MutableBuffer<T>,
+    private val bufferFactory: BufferFactory<T>,
     private var startIndex: Int = 0,
     size: Int = 0,
 ) : Buffer<T> {
+
+
     private val mutex: Mutex = Mutex()
 
+    public val capacity: Int get() = buffer.size
+
     override var size: Int = size
         private set
 
     override operator fun get(index: Int): T {
         require(index >= 0) { "Index must be positive" }
         require(index < size) { "Index $index is out of circular buffer size $size" }
-        return buffer[startIndex.forward(index)] as T
+        return buffer[startIndex.forward(index)]
     }
 
-    public fun isFull(): Boolean = size == buffer.size
+    public fun isFull(): Boolean = size == capacity
 
     /**
      * Iterator could provide wrong results if buffer is changed in initialization (iteration is safe)
@@ -39,11 +42,11 @@ public class RingBuffer<T>(
     override operator fun iterator(): Iterator<T> = object : AbstractIterator<T>() {
         private var count = size
         private var index = startIndex
-        val copy = buffer.copy()
+        val copy = buffer.copy(bufferFactory)
 
         override fun computeNext() {
             if (count == 0) done() else {
-                setNext(copy[index] as T)
+                setNext(copy[index])
                 index = index.forward(1)
                 count--
             }
@@ -54,10 +57,13 @@ public class RingBuffer<T>(
      * A safe snapshot operation
      */
     public suspend fun snapshot(): Buffer<T> = mutex.withLock {
-        val copy = buffer.copy()
-        VirtualBuffer(size) { i -> copy[startIndex.forward(i)] as T }
+        val copy = buffer.copy(bufferFactory)
+        VirtualBuffer(size) { i -> copy[startIndex.forward(i)] }
     }
 
+    /**
+     * Add an element to the end of the [RingBuffer]. If buffer capacity is reached, the first element is automatically removed.
+     */
     public suspend fun push(element: T) {
         mutex.withLock {
             buffer[startIndex.forward(size)] = element
@@ -65,24 +71,28 @@ public class RingBuffer<T>(
         }
     }
 
+    /**
+     * Reset buffer to its empty state
+     */
+    public suspend fun reset(): Unit = mutex.withLock {
+        startIndex = 0
+        size = 0
+    }
 
-    @Suppress("NOTHING_TO_INLINE")
-    private inline fun Int.forward(n: Int): Int = (this + n) % (buffer.size)
+    private fun Int.forward(n: Int): Int = (this + n) % capacity
 
     override fun toString(): String = Buffer.toString(this)
-
-    public companion object {
-        public inline fun <reified T : Any> build(size: Int, empty: T): RingBuffer<T> {
-            val buffer = MutableBuffer.auto(size) { empty } as MutableBuffer<T?>
-            return RingBuffer(buffer)
-        }
-
-        /**
-         * Slow yet universal buffer
-         */
-        public fun <T> boxing(size: Int): RingBuffer<T> {
-            val buffer: MutableBuffer<T?> = MutableBuffer.boxing(size) { null }
-            return RingBuffer(buffer)
-        }
-    }
+}
+
+public inline fun <reified T : Any> RingBuffer(size: Int, empty: T): RingBuffer<T> {
+    val buffer = MutableBuffer(size) { empty }
+    return RingBuffer(buffer, BufferFactory())
+}
+
+/**
+ * Slow yet universal buffer
+ */
+public fun <T> RingBuffer(size: Int, algebra: Group<T>): RingBuffer<T> {
+    val buffer: MutableBuffer<T> = MutableBuffer(algebra.type, size) { algebra.zero }
+    return RingBuffer(buffer, algebra.bufferFactory)
 }
diff --git a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt
index a62bcc6b8..7dc423552 100644
--- a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt
+++ b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt
index 22c2ac3ff..86e7bcfef 100644
--- a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt
+++ b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -17,6 +17,7 @@ public class LazyStructureND<out T>(
     override val shape: ShapeND,
     public val function: suspend (IntArray) -> T,
 ) : StructureND<T> {
+
     private val cache: MutableMap<IntArray, Deferred<T>> = HashMap()
 
     public fun async(index: IntArray): Deferred<T> = cache.getOrPut(index) {
@@ -24,6 +25,7 @@ public class LazyStructureND<out T>(
     }
 
     public suspend fun await(index: IntArray): T = async(index).await()
+
     @PerformancePitfall
     override operator fun get(index: IntArray): T = runBlocking { async(index).await() }
 
diff --git a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt
index c448168e3..22893389d 100644
--- a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt
+++ b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt
index a6d7f006c..701715123 100644
--- a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt
+++ b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,6 +7,7 @@ package space.kscience.kmath.streaming
 
 import kotlinx.coroutines.flow.*
 import kotlinx.coroutines.runBlocking
+import space.kscience.kmath.operations.Int32Ring
 import space.kscience.kmath.operations.asSequence
 import kotlin.test.Test
 import kotlin.test.assertEquals
@@ -14,7 +15,7 @@ import kotlin.test.assertEquals
 internal class RingBufferTest {
     @Test
     fun push() {
-        val buffer = RingBuffer.build(20, Double.NaN)
+        val buffer = RingBuffer(20, Double.NaN)
         runBlocking {
             for (i in 1..30) {
                 buffer.push(i.toDouble())
@@ -30,7 +31,7 @@ internal class RingBufferTest {
             while (true) emit(i++)
         }
 
-        val windowed = flow.windowed(10)
+        val windowed = flow.windowed(10, Int32Ring)
 
         runBlocking {
             @Suppress("UNUSED_VARIABLE") val first = windowed.take(1).single()
diff --git a/kmath-dimensions/README.md b/kmath-dimensions/README.md
index 2e7250b51..c7ea29b91 100644
--- a/kmath-dimensions/README.md
+++ b/kmath-dimensions/README.md
@@ -6,19 +6,8 @@ A proof of concept module for adding type-safe dimensions to structures
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-dimensions:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-dimensions:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-dimensions:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -27,6 +16,6 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-dimensions:0.4.0-dev-1")
+    implementation("space.kscience:kmath-dimensions:0.4.0")
 }
 ```
diff --git a/kmath-dimensions/build.gradle.kts b/kmath-dimensions/build.gradle.kts
index be1fc65a0..36f080899 100644
--- a/kmath-dimensions/build.gradle.kts
+++ b/kmath-dimensions/build.gradle.kts
@@ -2,12 +2,13 @@ plugins {
     id("space.kscience.gradle.mpp")
 }
 
-kscience{
+kscience {
     jvm()
     js()
     native()
+    wasm()
 
-    dependencies{
+    dependencies {
         api(projects.kmathCore)
     }
 
diff --git a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt
index 14677319c..afdb8eec1 100644
--- a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt
+++ b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt
index dde2d4fcf..7ddc143ad 100644
--- a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt
+++ b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,7 +8,7 @@ package space.kscience.kmath.dimensions
 import space.kscience.kmath.linear.*
 import space.kscience.kmath.nd.ShapeND
 import space.kscience.kmath.nd.Structure2D
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.Ring
 import space.kscience.kmath.operations.algebra
 import kotlin.jvm.JvmInline
@@ -48,6 +48,7 @@ public interface DMatrix<out T, R : Dimension, C : Dimension> : Structure2D<T> {
 public value class DMatrixWrapper<out T, R : Dimension, C : Dimension>(
     private val structure: Structure2D<T>,
 ) : DMatrix<T, R, C> {
+
     override val shape: ShapeND get() = structure.shape
     override val rowNum: Int get() = shape[0]
     override val colNum: Int get() = shape[1]
@@ -75,8 +76,8 @@ public interface DPoint<out T, D : Dimension> : Point<T> {
  * Dimension-safe point wrapper
  */
 @JvmInline
-public value class DPointWrapper<out T, D : Dimension>(public val point: Point<T>) :
-    DPoint<T, D> {
+public value class DPointWrapper<out T, D : Dimension>(public val point: Point<T>) : DPoint<T, D> {
+
     override val size: Int get() = point.size
 
     override operator fun get(index: Int): T = point[index]
@@ -146,11 +147,11 @@ public value class DMatrixContext<T : Any, out A : Ring<T>>(public val context:
     public inline operator fun <reified R : Dimension, reified C : Dimension> DMatrix<T, C, R>.unaryMinus(): DMatrix<T, C, R> =
         context.run { this@unaryMinus.unaryMinus() }.coerce()
 
-    public inline fun <reified R : Dimension, reified C : Dimension> DMatrix<T, C, R>.transpose(): DMatrix<T, R, C> =
-        context.run { (this@transpose as Matrix<T>).transpose() }.coerce()
+    public inline fun <reified R : Dimension, reified C : Dimension> DMatrix<T, C, R>.transposed(): DMatrix<T, R, C> =
+        context.run { (this@transposed as Matrix<T>).transposed() }.coerce()
 
     public companion object {
-        public val real: DMatrixContext<Double, DoubleField> = DMatrixContext(Double.algebra.linearSpace)
+        public val real: DMatrixContext<Double, Float64Field> = DMatrixContext(Double.algebra.linearSpace)
     }
 }
 
@@ -158,12 +159,12 @@ public value class DMatrixContext<T : Any, out A : Ring<T>>(public val context:
 /**
  * A square unit matrix
  */
-public inline fun <reified D : Dimension> DMatrixContext<Double, DoubleField>.one(): DMatrix<Double, D, D> =
+public inline fun <reified D : Dimension> DMatrixContext<Double, Float64Field>.one(): DMatrix<Double, D, D> =
     produce { i, j ->
         if (i == j) 1.0 else 0.0
     }
 
-public inline fun <reified R : Dimension, reified C : Dimension> DMatrixContext<Double, DoubleField>.zero(): DMatrix<Double, R, C> =
+public inline fun <reified R : Dimension, reified C : Dimension> DMatrixContext<Double, Float64Field>.zero(): DMatrix<Double, R, C> =
     produce { _, _ ->
         0.0
     }
diff --git a/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt b/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt
index e2793855b..b236f6bf9 100644
--- a/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt
+++ b/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -30,7 +30,7 @@ internal class DMatrixContextTest {
             val m2 = produce<D3, D2> { i, j -> (i + j).toDouble() }
 
             //Dimension-safe addition
-            m1.transpose() + m2
+            m1.transposed() + m2
         }
     }
 }
diff --git a/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt
index 1ae484228..cbf404b7f 100644
--- a/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt
+++ b/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt
index 24cfb14e8..131a6db42 100644
--- a/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt
+++ b/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt
index f5f749c8a..ddfee4523 100644
--- a/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt
+++ b/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-dimensions/src/wasmJsMain/kotlin/space/kscience/kmath/dimensions/Dimension.wasmJs.kt b/kmath-dimensions/src/wasmJsMain/kotlin/space/kscience/kmath/dimensions/Dimension.wasmJs.kt
new file mode 100644
index 000000000..cbf404b7f
--- /dev/null
+++ b/kmath-dimensions/src/wasmJsMain/kotlin/space/kscience/kmath/dimensions/Dimension.wasmJs.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.dimensions
+
+import kotlin.reflect.KClass
+
+private val dimensionMap: MutableMap<Int, Dimension> = hashMapOf(1 to D1, 2 to D2, 3 to D3)
+
+@Suppress("UNCHECKED_CAST")
+public actual fun <D : Dimension> Dimension.Companion.resolve(type: KClass<D>): D = dimensionMap
+    .entries
+    .map(MutableMap.MutableEntry<Int, Dimension>::value)
+    .find { it::class == type } as? D
+    ?: error("Can't resolve dimension $type")
+
+public actual fun Dimension.Companion.of(dim: Int): Dimension = dimensionMap.getOrPut(dim) {
+    object : Dimension {
+        override val dim: Int get() = dim
+    }
+}
diff --git a/kmath-ejml/README.md b/kmath-ejml/README.md
index ad80ba183..92ec252c1 100644
--- a/kmath-ejml/README.md
+++ b/kmath-ejml/README.md
@@ -9,19 +9,8 @@ EJML based linear algebra implementation.
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-ejml:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-ejml:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-ejml:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -30,6 +19,6 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-ejml:0.4.0-dev-1")
+    implementation("space.kscience:kmath-ejml:0.4.0")
 }
 ```
diff --git a/kmath-ejml/build.gradle.kts b/kmath-ejml/build.gradle.kts
index d7f780d79..54b8f7038 100644
--- a/kmath-ejml/build.gradle.kts
+++ b/kmath-ejml/build.gradle.kts
@@ -1,15 +1,15 @@
-import space.kscience.kmath.ejml.codegen.ejmlCodegen
-
 plugins {
     id("space.kscience.gradle.jvm")
 }
 
+val ejmlVerision = "0.43.1"
+
 dependencies {
-    api("org.ejml:ejml-ddense:0.41")
-    api("org.ejml:ejml-fdense:0.41")
-    api("org.ejml:ejml-dsparse:0.41")
-    api("org.ejml:ejml-fsparse:0.41")
-    api(project(":kmath-core"))
+    api("org.ejml:ejml-ddense:$ejmlVerision")
+    api("org.ejml:ejml-fdense:$ejmlVerision")
+    api("org.ejml:ejml-dsparse:$ejmlVerision")
+    api("org.ejml:ejml-fsparse:$ejmlVerision")
+    api(projects.kmathCore)
 }
 
 readme {
@@ -32,10 +32,10 @@ readme {
     ) { "LinearSpace implementations." }
 }
 
-kotlin.sourceSets.main {
-    val codegen by tasks.creating {
-        ejmlCodegen(kotlin.srcDirs.first().absolutePath + "/space/kscience/kmath/ejml/_generated.kt")
-    }
-
-    kotlin.srcDirs(files().builtBy(codegen))
-}
+//kotlin.sourceSets.main {
+//    val codegen by tasks.creating {
+//        ejmlCodegen(kotlin.srcDirs.first().absolutePath + "/space/kscience/kmath/ejml/_generated.kt")
+//    }
+//
+//    kotlin.srcDirs(files().builtBy(codegen))
+//}
diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt
index 8925fb045..d5bd8ccb7 100644
--- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt
+++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt
@@ -1,16 +1,13 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.ejml
 
 import space.kscience.kmath.UnstableKMathAPI
-import space.kscience.kmath.linear.InverseMatrixFeature
-import space.kscience.kmath.linear.LinearSpace
-import space.kscience.kmath.linear.Matrix
-import space.kscience.kmath.linear.Point
-import space.kscience.kmath.nd.Structure2D
+import space.kscience.kmath.linear.*
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.Ring
 
 /**
@@ -40,8 +37,7 @@ public abstract class EjmlLinearSpace<T : Any, out A : Ring<T>, out M : org.ejml
 
     public abstract override fun buildVector(size: Int, initializer: A.(Int) -> T): EjmlVector<T, M>
 
-    @Suppress("UNCHECKED_CAST")
     @UnstableKMathAPI
-    public fun EjmlMatrix<T, *>.inverse(): Structure2D<Double> =
-        computeFeature(this, InverseMatrixFeature::class)?.inverse as Structure2D<Double>
+    public fun EjmlMatrix<T, *>.inverted(): Matrix<Double> =
+        computeAttribute(this, Float64Field.linearSpace.Inverted)!!
 }
diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt
index 1d70c0e7d..d24f56042 100644
--- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt
+++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt
index c4fae9951..82401ba05 100644
--- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt
+++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/implementations.kt
similarity index 69%
rename from kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt
rename to kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/implementations.kt
index c56583fa8..df4941c52 100644
--- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt
+++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/implementations.kt
@@ -1,6 +1,6 @@
 /*
- * Copyright 2018-2021 KMath contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 /* This file is generated with buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt */
@@ -17,19 +17,18 @@ import org.ejml.sparse.csc.CommonOps_DSCC
 import org.ejml.sparse.csc.CommonOps_FSCC
 import org.ejml.sparse.csc.factory.DecompositionFactory_DSCC
 import org.ejml.sparse.csc.factory.DecompositionFactory_FSCC
-import org.ejml.sparse.csc.factory.LinearSolverFactory_DSCC
-import org.ejml.sparse.csc.factory.LinearSolverFactory_FSCC
-import space.kscience.kmath.UnstableKMathAPI
+import space.kscience.attributes.SafeType
+import space.kscience.attributes.safeTypeOf
 import space.kscience.kmath.linear.*
 import space.kscience.kmath.linear.Matrix
-import space.kscience.kmath.nd.StructureFeature
-import space.kscience.kmath.operations.DoubleField
-import space.kscience.kmath.operations.FloatField
+import space.kscience.kmath.nd.Structure2D
+import space.kscience.kmath.nd.StructureAttribute
+import space.kscience.kmath.operations.Float32Field
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.invoke
-import space.kscience.kmath.structures.DoubleBuffer
-import space.kscience.kmath.structures.FloatBuffer
-import kotlin.reflect.KClass
-import kotlin.reflect.cast
+import space.kscience.kmath.structures.Float32
+import space.kscience.kmath.structures.IntBuffer
+import space.kscience.kmath.structures.asBuffer
 
 /**
  * [EjmlVector] specialization for [Double].
@@ -39,6 +38,7 @@ public class EjmlDoubleVector<out M : DMatrix>(override val origin: M) : EjmlVec
         require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" }
     }
 
+
     override operator fun get(index: Int): Double = origin[0, index]
 }
 
@@ -64,18 +64,22 @@ public class EjmlDoubleMatrix<out M : DMatrix>(override val origin: M) : EjmlMat
  * [EjmlMatrix] specialization for [Float].
  */
 public class EjmlFloatMatrix<out M : FMatrix>(override val origin: M) : EjmlMatrix<Float, M>(origin) {
+
     override operator fun get(i: Int, j: Int): Float = origin[i, j]
 }
 
+
 /**
  * [EjmlLinearSpace] implementation based on [CommonOps_DDRM], [DecompositionFactory_DDRM] operations and
  * [DMatrixRMaj] matrices.
  */
-public object EjmlLinearSpaceDDRM : EjmlLinearSpace<Double, DoubleField, DMatrixRMaj>() {
+public object EjmlLinearSpaceDDRM : EjmlLinearSpace<Double, Float64Field, DMatrixRMaj>() {
     /**
-     * The [DoubleField] reference.
+     * The [Float64Field] reference.
      */
-    override val elementAlgebra: DoubleField get() = DoubleField
+    override val elementAlgebra: Float64Field get() = Float64Field
+
+    override val type: SafeType<Double> get() = safeTypeOf()
 
     @Suppress("UNCHECKED_CAST")
     override fun Matrix<Double>.toEjml(): EjmlDoubleMatrix<DMatrixRMaj> = when {
@@ -94,7 +98,7 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace<Double, DoubleField, DMatrix
     override fun buildMatrix(
         rows: Int,
         columns: Int,
-        initializer: DoubleField.(i: Int, j: Int) -> Double,
+        initializer: Float64Field.(i: Int, j: Int) -> Double,
     ): EjmlDoubleMatrix<DMatrixRMaj> = DMatrixRMaj(rows, columns).also {
         (0 until rows).forEach { row ->
             (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) }
@@ -103,7 +107,7 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace<Double, DoubleField, DMatrix
 
     override fun buildVector(
         size: Int,
-        initializer: DoubleField.(Int) -> Double,
+        initializer: Float64Field.(Int) -> Double,
     ): EjmlDoubleVector<DMatrixRMaj> = EjmlDoubleVector(DMatrixRMaj(size, 1).also {
         (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) }
     })
@@ -129,10 +133,10 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace<Double, DoubleField, DMatrix
         val out = DMatrixRMaj(1, 1)
 
         CommonOps_DDRM.add(
-            elementAlgebra.one, 
-            toEjml().origin, 
+            elementAlgebra.one,
+            toEjml().origin,
             elementAlgebra { -one },
-            other.toEjml().origin, 
+            other.toEjml().origin,
             out,
         )
 
@@ -153,12 +157,12 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace<Double, DoubleField, DMatrix
 
     override fun Matrix<Double>.plus(other: Matrix<Double>): EjmlDoubleMatrix<DMatrixRMaj> {
         val out = DMatrixRMaj(1, 1)
-        
+
         CommonOps_DDRM.add(
             elementAlgebra.one,
             toEjml().origin,
             elementAlgebra.one,
-            other.toEjml().origin, 
+            other.toEjml().origin,
             out,
         )
 
@@ -203,77 +207,65 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace<Double, DoubleField, DMatrix
 
     override fun Double.times(v: Point<Double>): EjmlDoubleVector<DMatrixRMaj> = v * this
 
-    @UnstableKMathAPI
-    override fun <F : StructureFeature> computeFeature(structure: Matrix<Double>, type: KClass<out F>): F? {
-        structure.getFeature(type)?.let { return it }
+    override fun <V, A : StructureAttribute<V>> computeAttribute(structure: Structure2D<Double>, attribute: A): V? {
         val origin = structure.toEjml().origin
 
-        return when (type) {
-            InverseMatrixFeature::class -> object : InverseMatrixFeature<Double> {
-                override val inverse: Matrix<Double> by lazy {
-                    val res = origin.copy()
-                    CommonOps_DDRM.invert(res)
-                    res.wrapMatrix()
-                }
+        val raw: Any? = when (attribute) {
+            Inverted -> {
+                val res = origin.copy()
+                CommonOps_DDRM.invert(res)
+                res.wrapMatrix()
             }
 
-            DeterminantFeature::class -> object : DeterminantFeature<Double> {
-                override val determinant: Double by lazy { CommonOps_DDRM.det(origin) }
-            }
-
-            SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature<Double> {
-                private val svd by lazy {
-                    DecompositionFactory_DDRM.svd(origin.numRows, origin.numCols, true, true, false)
+            Determinant -> CommonOps_DDRM.det(origin)
+            SVD -> object : SingularValueDecomposition<Double> {
+                val ejmlSvd by lazy {
+                    DecompositionFactory_DDRM
+                        .svd(origin.numRows, origin.numCols, true, true, false)
                         .apply { decompose(origin.copy()) }
                 }
+                override val u: Matrix<Double> get() = ejmlSvd.getU(null, false).wrapMatrix()
+
+                override val s: Matrix<Double> get() = ejmlSvd.getW(null).wrapMatrix()
+                override val v: Matrix<Double> get() = ejmlSvd.getV(null, false).wrapMatrix()
+                override val singularValues: Point<Double> get() = ejmlSvd.singularValues.asBuffer()
 
-                override val u: Matrix<Double> by lazy { svd.getU(null, false).wrapMatrix() }
-                override val s: Matrix<Double> by lazy { svd.getW(null).wrapMatrix() }
-                override val v: Matrix<Double> by lazy { svd.getV(null, false).wrapMatrix() }
-                override val singularValues: Point<Double> by lazy { DoubleBuffer(svd.singularValues) }
             }
 
-            QRDecompositionFeature::class -> object : QRDecompositionFeature<Double> {
-                private val qr by lazy {
-                    DecompositionFactory_DDRM.qr().apply { decompose(origin.copy()) }
-                }
-
-                override val q: Matrix<Double> by lazy {
-                    qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature)
-                }
-
-                override val r: Matrix<Double> by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) }
+            QR -> object : QRDecomposition<Double> {
+                val ejmlQr by lazy { DecompositionFactory_DDRM.qr().apply { decompose(origin.copy()) } }
+                override val q: Matrix<Double> get() = ejmlQr.getQ(null, false).wrapMatrix()
+                override val r: Matrix<Double> get() = ejmlQr.getR(null, false).wrapMatrix()
             }
 
-            CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<Double> {
+            Cholesky -> object : CholeskyDecomposition<Double> {
                 override val l: Matrix<Double> by lazy {
                     val cholesky =
                         DecompositionFactory_DDRM.chol(structure.rowNum, true).apply { decompose(origin.copy()) }
 
-                    cholesky.getT(null).wrapMatrix().withFeature(LFeature)
+                    cholesky.getT(null).wrapMatrix().withAttribute(LowerTriangular)
                 }
             }
 
-            LupDecompositionFeature::class -> object : LupDecompositionFeature<Double> {
+            LUP -> object : LupDecomposition<Double> {
                 private val lup by lazy {
                     DecompositionFactory_DDRM.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) }
                 }
 
-                override val l: Matrix<Double> by lazy {
-                    lup.getLower(null).wrapMatrix().withFeature(LFeature)
-                }
+                override val l: Matrix<Double>
+                    get() = lup.getLower(null).wrapMatrix().withAttribute(LowerTriangular)
 
-                override val u: Matrix<Double> by lazy {
-                    lup.getUpper(null).wrapMatrix().withFeature(UFeature)
-                }
 
-                override val p: Matrix<Double> by lazy { lup.getRowPivot(null).wrapMatrix() }
+                override val u: Matrix<Double>
+                    get() = lup.getUpper(null).wrapMatrix().withAttribute(UpperTriangular)
+                override val pivot: IntBuffer get() = lup.getRowPivotV(null).asBuffer()
             }
 
             else -> null
-        }?.let{
-            type.cast(it)
         }
+
+        @Suppress("UNCHECKED_CAST")
+        return raw as V?
     }
 
     /**
@@ -303,15 +295,18 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace<Double, DoubleField, DMatrix
     }
 }
 
+
 /**
  * [EjmlLinearSpace] implementation based on [CommonOps_FDRM], [DecompositionFactory_FDRM] operations and
  * [FMatrixRMaj] matrices.
  */
-public object EjmlLinearSpaceFDRM : EjmlLinearSpace<Float, FloatField, FMatrixRMaj>() {
+public object EjmlLinearSpaceFDRM : EjmlLinearSpace<Float, Float32Field, FMatrixRMaj>() {
     /**
-     * The [FloatField] reference.
+     * The [Float32Field] reference.
      */
-    override val elementAlgebra: FloatField get() = FloatField
+    override val elementAlgebra: Float32Field get() = Float32Field
+
+    override val type: SafeType<Float> get() = safeTypeOf()
 
     @Suppress("UNCHECKED_CAST")
     override fun Matrix<Float>.toEjml(): EjmlFloatMatrix<FMatrixRMaj> = when {
@@ -330,7 +325,7 @@ public object EjmlLinearSpaceFDRM : EjmlLinearSpace<Float, FloatField, FMatrixRM
     override fun buildMatrix(
         rows: Int,
         columns: Int,
-        initializer: FloatField.(i: Int, j: Int) -> Float,
+        initializer: Float32Field.(i: Int, j: Int) -> Float,
     ): EjmlFloatMatrix<FMatrixRMaj> = FMatrixRMaj(rows, columns).also {
         (0 until rows).forEach { row ->
             (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) }
@@ -339,7 +334,7 @@ public object EjmlLinearSpaceFDRM : EjmlLinearSpace<Float, FloatField, FMatrixRM
 
     override fun buildVector(
         size: Int,
-        initializer: FloatField.(Int) -> Float,
+        initializer: Float32Field.(Int) -> Float,
     ): EjmlFloatVector<FMatrixRMaj> = EjmlFloatVector(FMatrixRMaj(size, 1).also {
         (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) }
     })
@@ -365,10 +360,10 @@ public object EjmlLinearSpaceFDRM : EjmlLinearSpace<Float, FloatField, FMatrixRM
         val out = FMatrixRMaj(1, 1)
 
         CommonOps_FDRM.add(
-            elementAlgebra.one, 
-            toEjml().origin, 
+            elementAlgebra.one,
+            toEjml().origin,
             elementAlgebra { -one },
-            other.toEjml().origin, 
+            other.toEjml().origin,
             out,
         )
 
@@ -389,12 +384,12 @@ public object EjmlLinearSpaceFDRM : EjmlLinearSpace<Float, FloatField, FMatrixRM
 
     override fun Matrix<Float>.plus(other: Matrix<Float>): EjmlFloatMatrix<FMatrixRMaj> {
         val out = FMatrixRMaj(1, 1)
-        
+
         CommonOps_FDRM.add(
             elementAlgebra.one,
             toEjml().origin,
             elementAlgebra.one,
-            other.toEjml().origin, 
+            other.toEjml().origin,
             out,
         )
 
@@ -439,77 +434,65 @@ public object EjmlLinearSpaceFDRM : EjmlLinearSpace<Float, FloatField, FMatrixRM
 
     override fun Float.times(v: Point<Float>): EjmlFloatVector<FMatrixRMaj> = v * this
 
-    @UnstableKMathAPI
-    override fun <F : StructureFeature> computeFeature(structure: Matrix<Float>, type: KClass<out F>): F? {
-        structure.getFeature(type)?.let { return it }
+    override fun <V, A : StructureAttribute<V>> computeAttribute(structure: Structure2D<Float32>, attribute: A): V? {
         val origin = structure.toEjml().origin
 
-        return when (type) {
-            InverseMatrixFeature::class -> object : InverseMatrixFeature<Float> {
-                override val inverse: Matrix<Float> by lazy {
-                    val res = origin.copy()
-                    CommonOps_FDRM.invert(res)
-                    res.wrapMatrix()
-                }
+        val raw: Any? = when (attribute) {
+            Inverted -> {
+                val res = origin.copy()
+                CommonOps_FDRM.invert(res)
+                res.wrapMatrix()
             }
 
-            DeterminantFeature::class -> object : DeterminantFeature<Float> {
-                override val determinant: Float by lazy { CommonOps_FDRM.det(origin) }
-            }
-
-            SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature<Float> {
-                private val svd by lazy {
-                    DecompositionFactory_FDRM.svd(origin.numRows, origin.numCols, true, true, false)
+            Determinant -> CommonOps_FDRM.det(origin)
+            SVD -> object : SingularValueDecomposition<Float32> {
+                val ejmlSvd by lazy {
+                    DecompositionFactory_FDRM
+                        .svd(origin.numRows, origin.numCols, true, true, false)
                         .apply { decompose(origin.copy()) }
                 }
+                override val u: Matrix<Float32> get() = ejmlSvd.getU(null, false).wrapMatrix()
+
+                override val s: Matrix<Float32> get() = ejmlSvd.getW(null).wrapMatrix()
+                override val v: Matrix<Float32> get() = ejmlSvd.getV(null, false).wrapMatrix()
+                override val singularValues: Point<Float32> get() = ejmlSvd.singularValues.asBuffer()
 
-                override val u: Matrix<Float> by lazy { svd.getU(null, false).wrapMatrix() }
-                override val s: Matrix<Float> by lazy { svd.getW(null).wrapMatrix() }
-                override val v: Matrix<Float> by lazy { svd.getV(null, false).wrapMatrix() }
-                override val singularValues: Point<Float> by lazy { FloatBuffer(svd.singularValues) }
             }
 
-            QRDecompositionFeature::class -> object : QRDecompositionFeature<Float> {
-                private val qr by lazy {
-                    DecompositionFactory_FDRM.qr().apply { decompose(origin.copy()) }
-                }
-
-                override val q: Matrix<Float> by lazy {
-                    qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature)
-                }
-
-                override val r: Matrix<Float> by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) }
+            QR -> object : QRDecomposition<Float32> {
+                val ejmlQr by lazy { DecompositionFactory_FDRM.qr().apply { decompose(origin.copy()) } }
+                override val q: Matrix<Float32> get() = ejmlQr.getQ(null, false).wrapMatrix()
+                override val r: Matrix<Float32> get() = ejmlQr.getR(null, false).wrapMatrix()
             }
 
-            CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<Float> {
-                override val l: Matrix<Float> by lazy {
+            Cholesky -> object : CholeskyDecomposition<Float32> {
+                override val l: Matrix<Float32> by lazy {
                     val cholesky =
                         DecompositionFactory_FDRM.chol(structure.rowNum, true).apply { decompose(origin.copy()) }
 
-                    cholesky.getT(null).wrapMatrix().withFeature(LFeature)
+                    cholesky.getT(null).wrapMatrix().withAttribute(LowerTriangular)
                 }
             }
 
-            LupDecompositionFeature::class -> object : LupDecompositionFeature<Float> {
+            LUP -> object : LupDecomposition<Float32> {
                 private val lup by lazy {
                     DecompositionFactory_FDRM.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) }
                 }
 
-                override val l: Matrix<Float> by lazy {
-                    lup.getLower(null).wrapMatrix().withFeature(LFeature)
-                }
+                override val l: Matrix<Float32>
+                    get() = lup.getLower(null).wrapMatrix().withAttribute(LowerTriangular)
 
-                override val u: Matrix<Float> by lazy {
-                    lup.getUpper(null).wrapMatrix().withFeature(UFeature)
-                }
 
-                override val p: Matrix<Float> by lazy { lup.getRowPivot(null).wrapMatrix() }
+                override val u: Matrix<Float32>
+                    get() = lup.getUpper(null).wrapMatrix().withAttribute(UpperTriangular)
+                override val pivot: IntBuffer get() = lup.getRowPivotV(null).asBuffer()
             }
 
             else -> null
-        }?.let{
-            type.cast(it)
         }
+
+        @Suppress("UNCHECKED_CAST")
+        return raw as V?
     }
 
     /**
@@ -539,15 +522,18 @@ public object EjmlLinearSpaceFDRM : EjmlLinearSpace<Float, FloatField, FMatrixRM
     }
 }
 
+
 /**
  * [EjmlLinearSpace] implementation based on [CommonOps_DSCC], [DecompositionFactory_DSCC] operations and
  * [DMatrixSparseCSC] matrices.
  */
-public object EjmlLinearSpaceDSCC : EjmlLinearSpace<Double, DoubleField, DMatrixSparseCSC>() {
+public object EjmlLinearSpaceDSCC : EjmlLinearSpace<Double, Float64Field, DMatrixSparseCSC>() {
     /**
-     * The [DoubleField] reference.
+     * The [Float64Field] reference.
      */
-    override val elementAlgebra: DoubleField get() = DoubleField
+    override val elementAlgebra: Float64Field get() = Float64Field
+
+    override val type: SafeType<Double> get() = safeTypeOf()
 
     @Suppress("UNCHECKED_CAST")
     override fun Matrix<Double>.toEjml(): EjmlDoubleMatrix<DMatrixSparseCSC> = when {
@@ -566,7 +552,7 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace<Double, DoubleField, DMatrix
     override fun buildMatrix(
         rows: Int,
         columns: Int,
-        initializer: DoubleField.(i: Int, j: Int) -> Double,
+        initializer: Float64Field.(i: Int, j: Int) -> Double,
     ): EjmlDoubleMatrix<DMatrixSparseCSC> = DMatrixSparseCSC(rows, columns).also {
         (0 until rows).forEach { row ->
             (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) }
@@ -575,7 +561,7 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace<Double, DoubleField, DMatrix
 
     override fun buildVector(
         size: Int,
-        initializer: DoubleField.(Int) -> Double,
+        initializer: Float64Field.(Int) -> Double,
     ): EjmlDoubleVector<DMatrixSparseCSC> = EjmlDoubleVector(DMatrixSparseCSC(size, 1).also {
         (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) }
     })
@@ -601,12 +587,12 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace<Double, DoubleField, DMatrix
         val out = DMatrixSparseCSC(1, 1)
 
         CommonOps_DSCC.add(
-            elementAlgebra.one, 
-            toEjml().origin, 
+            elementAlgebra.one,
+            toEjml().origin,
             elementAlgebra { -one },
-            other.toEjml().origin, 
+            other.toEjml().origin,
             out,
-            null, 
+            null,
             null,
         )
 
@@ -627,14 +613,14 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace<Double, DoubleField, DMatrix
 
     override fun Matrix<Double>.plus(other: Matrix<Double>): EjmlDoubleMatrix<DMatrixSparseCSC> {
         val out = DMatrixSparseCSC(1, 1)
-        
+
         CommonOps_DSCC.add(
             elementAlgebra.one,
             toEjml().origin,
             elementAlgebra.one,
-            other.toEjml().origin, 
+            other.toEjml().origin,
             out,
-            null, 
+            null,
             null,
         )
 
@@ -650,7 +636,7 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace<Double, DoubleField, DMatrix
             elementAlgebra.one,
             other.toEjml().origin,
             out,
-            null, 
+            null,
             null,
         )
 
@@ -666,7 +652,7 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace<Double, DoubleField, DMatrix
             elementAlgebra { -one },
             other.toEjml().origin,
             out,
-            null, 
+            null,
             null,
         )
 
@@ -683,64 +669,54 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace<Double, DoubleField, DMatrix
 
     override fun Double.times(v: Point<Double>): EjmlDoubleVector<DMatrixSparseCSC> = v * this
 
-    @UnstableKMathAPI
-    override fun <F : StructureFeature> computeFeature(structure: Matrix<Double>, type: KClass<out F>): F? {
-        structure.getFeature(type)?.let { return it }
+    override fun <V, A : StructureAttribute<V>> computeAttribute(structure: Structure2D<Double>, attribute: A): V? {
         val origin = structure.toEjml().origin
 
-        return when (type) {
-            QRDecompositionFeature::class -> object : QRDecompositionFeature<Double> {
-                private val qr by lazy {
-                    DecompositionFactory_DSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) }
-                }
-
-                override val q: Matrix<Double> by lazy {
-                    qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature)
-                }
-
-                override val r: Matrix<Double> by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) }
+        val raw: Any? = when (attribute) {
+            Inverted -> {
+                val res = DMatrixRMaj(origin.numRows, origin.numCols)
+                CommonOps_DSCC.invert(origin, res)
+                res.wrapMatrix()
             }
 
-            CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<Double> {
+            Determinant -> CommonOps_DSCC.det(origin)
+
+            QR -> object : QRDecomposition<Double> {
+                val ejmlQr by lazy {
+                    DecompositionFactory_DSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) }
+                }
+                override val q: Matrix<Double> get() = ejmlQr.getQ(null, false).wrapMatrix()
+                override val r: Matrix<Double> get() = ejmlQr.getR(null, false).wrapMatrix()
+            }
+
+            Cholesky -> object : CholeskyDecomposition<Double> {
                 override val l: Matrix<Double> by lazy {
                     val cholesky =
                         DecompositionFactory_DSCC.cholesky().apply { decompose(origin.copy()) }
 
-                    (cholesky.getT(null) as DMatrix).wrapMatrix().withFeature(LFeature)
+                    (cholesky.getT(null) as DMatrix).wrapMatrix().withAttribute(LowerTriangular)
                 }
             }
 
-            LUDecompositionFeature::class, DeterminantFeature::class, InverseMatrixFeature::class -> object :
-                LUDecompositionFeature<Double>, DeterminantFeature<Double>, InverseMatrixFeature<Double> {
-                private val lu by lazy {
+            LUP -> object : LupDecomposition<Double> {
+                private val lup by lazy {
                     DecompositionFactory_DSCC.lu(FillReducing.NONE).apply { decompose(origin.copy()) }
                 }
 
-                override val l: Matrix<Double> by lazy {
-                    lu.getLower(null).wrapMatrix().withFeature(LFeature)
-                }
+                override val l: Matrix<Double>
+                    get() = lup.getLower(null).wrapMatrix().withAttribute(LowerTriangular)
 
-                override val u: Matrix<Double> by lazy {
-                    lu.getUpper(null).wrapMatrix().withFeature(UFeature)
-                }
 
-                override val inverse: Matrix<Double> by lazy {
-                    var a = origin
-                    val inverse = DMatrixRMaj(1, 1)
-                    val solver = LinearSolverFactory_DSCC.lu(FillReducing.NONE)
-                    if (solver.modifiesA()) a = a.copy()
-                    val i = CommonOps_DDRM.identity(a.numRows)
-                    solver.solve(i, inverse)
-                    inverse.wrapMatrix()
-                }
-
-                override val determinant: Double by lazy { elementAlgebra.number(lu.computeDeterminant().real) }
+                override val u: Matrix<Double>
+                    get() = lup.getUpper(null).wrapMatrix().withAttribute(UpperTriangular)
+                override val pivot: IntBuffer get() = lup.getRowPivotV(null).asBuffer()
             }
 
             else -> null
-        }?.let{
-            type.cast(it)
         }
+
+        @Suppress("UNCHECKED_CAST")
+        return raw as V?
     }
 
     /**
@@ -770,15 +746,18 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace<Double, DoubleField, DMatrix
     }
 }
 
+
 /**
  * [EjmlLinearSpace] implementation based on [CommonOps_FSCC], [DecompositionFactory_FSCC] operations and
  * [FMatrixSparseCSC] matrices.
  */
-public object EjmlLinearSpaceFSCC : EjmlLinearSpace<Float, FloatField, FMatrixSparseCSC>() {
+public object EjmlLinearSpaceFSCC : EjmlLinearSpace<Float, Float32Field, FMatrixSparseCSC>() {
     /**
-     * The [FloatField] reference.
+     * The [Float32Field] reference.
      */
-    override val elementAlgebra: FloatField get() = FloatField
+    override val elementAlgebra: Float32Field get() = Float32Field
+
+    override val type: SafeType<Float> get() = safeTypeOf()
 
     @Suppress("UNCHECKED_CAST")
     override fun Matrix<Float>.toEjml(): EjmlFloatMatrix<FMatrixSparseCSC> = when {
@@ -797,7 +776,7 @@ public object EjmlLinearSpaceFSCC : EjmlLinearSpace<Float, FloatField, FMatrixSp
     override fun buildMatrix(
         rows: Int,
         columns: Int,
-        initializer: FloatField.(i: Int, j: Int) -> Float,
+        initializer: Float32Field.(i: Int, j: Int) -> Float,
     ): EjmlFloatMatrix<FMatrixSparseCSC> = FMatrixSparseCSC(rows, columns).also {
         (0 until rows).forEach { row ->
             (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) }
@@ -806,7 +785,7 @@ public object EjmlLinearSpaceFSCC : EjmlLinearSpace<Float, FloatField, FMatrixSp
 
     override fun buildVector(
         size: Int,
-        initializer: FloatField.(Int) -> Float,
+        initializer: Float32Field.(Int) -> Float,
     ): EjmlFloatVector<FMatrixSparseCSC> = EjmlFloatVector(FMatrixSparseCSC(size, 1).also {
         (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) }
     })
@@ -832,12 +811,12 @@ public object EjmlLinearSpaceFSCC : EjmlLinearSpace<Float, FloatField, FMatrixSp
         val out = FMatrixSparseCSC(1, 1)
 
         CommonOps_FSCC.add(
-            elementAlgebra.one, 
-            toEjml().origin, 
+            elementAlgebra.one,
+            toEjml().origin,
             elementAlgebra { -one },
-            other.toEjml().origin, 
+            other.toEjml().origin,
             out,
-            null, 
+            null,
             null,
         )
 
@@ -858,14 +837,14 @@ public object EjmlLinearSpaceFSCC : EjmlLinearSpace<Float, FloatField, FMatrixSp
 
     override fun Matrix<Float>.plus(other: Matrix<Float>): EjmlFloatMatrix<FMatrixSparseCSC> {
         val out = FMatrixSparseCSC(1, 1)
-        
+
         CommonOps_FSCC.add(
             elementAlgebra.one,
             toEjml().origin,
             elementAlgebra.one,
-            other.toEjml().origin, 
+            other.toEjml().origin,
             out,
-            null, 
+            null,
             null,
         )
 
@@ -881,7 +860,7 @@ public object EjmlLinearSpaceFSCC : EjmlLinearSpace<Float, FloatField, FMatrixSp
             elementAlgebra.one,
             other.toEjml().origin,
             out,
-            null, 
+            null,
             null,
         )
 
@@ -897,7 +876,7 @@ public object EjmlLinearSpaceFSCC : EjmlLinearSpace<Float, FloatField, FMatrixSp
             elementAlgebra { -one },
             other.toEjml().origin,
             out,
-            null, 
+            null,
             null,
         )
 
@@ -913,65 +892,54 @@ public object EjmlLinearSpaceFSCC : EjmlLinearSpace<Float, FloatField, FMatrixSp
     }
 
     override fun Float.times(v: Point<Float>): EjmlFloatVector<FMatrixSparseCSC> = v * this
-
-    @UnstableKMathAPI
-    override fun <F : StructureFeature> computeFeature(structure: Matrix<Float>, type: KClass<out F>): F? {
-        structure.getFeature(type)?.let { return it }
+    override fun <V, A : StructureAttribute<V>> computeAttribute(structure: Structure2D<Float32>, attribute: A): V? {
         val origin = structure.toEjml().origin
 
-        return when (type) {
-            QRDecompositionFeature::class -> object : QRDecompositionFeature<Float> {
-                private val qr by lazy {
-                    DecompositionFactory_FSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) }
-                }
-
-                override val q: Matrix<Float> by lazy {
-                    qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature)
-                }
-
-                override val r: Matrix<Float> by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) }
+        val raw: Any? = when (attribute) {
+            Inverted -> {
+                val res = FMatrixRMaj(origin.numRows, origin.numCols)
+                CommonOps_FSCC.invert(origin, res)
+                res.wrapMatrix()
             }
 
-            CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<Float> {
-                override val l: Matrix<Float> by lazy {
+            Determinant -> CommonOps_FSCC.det(origin)
+
+            QR -> object : QRDecomposition<Float32> {
+                val ejmlQr by lazy {
+                    DecompositionFactory_FSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) }
+                }
+                override val q: Matrix<Float32> get() = ejmlQr.getQ(null, false).wrapMatrix()
+                override val r: Matrix<Float32> get() = ejmlQr.getR(null, false).wrapMatrix()
+            }
+
+            Cholesky -> object : CholeskyDecomposition<Float32> {
+                override val l: Matrix<Float32> by lazy {
                     val cholesky =
                         DecompositionFactory_FSCC.cholesky().apply { decompose(origin.copy()) }
 
-                    (cholesky.getT(null) as FMatrix).wrapMatrix().withFeature(LFeature)
+                    (cholesky.getT(null) as FMatrix).wrapMatrix().withAttribute(LowerTriangular)
                 }
             }
 
-            LUDecompositionFeature::class, DeterminantFeature::class, InverseMatrixFeature::class -> object :
-                LUDecompositionFeature<Float>, DeterminantFeature<Float>, InverseMatrixFeature<Float> {
-                private val lu by lazy {
+            LUP -> object : LupDecomposition<Float32> {
+                private val lup by lazy {
                     DecompositionFactory_FSCC.lu(FillReducing.NONE).apply { decompose(origin.copy()) }
                 }
 
-                override val l: Matrix<Float> by lazy {
-                    lu.getLower(null).wrapMatrix().withFeature(LFeature)
-                }
+                override val l: Matrix<Float32>
+                    get() = lup.getLower(null).wrapMatrix().withAttribute(LowerTriangular)
 
-                override val u: Matrix<Float> by lazy {
-                    lu.getUpper(null).wrapMatrix().withFeature(UFeature)
-                }
 
-                override val inverse: Matrix<Float> by lazy {
-                    var a = origin
-                    val inverse = FMatrixRMaj(1, 1)
-                    val solver = LinearSolverFactory_FSCC.lu(FillReducing.NONE)
-                    if (solver.modifiesA()) a = a.copy()
-                    val i = CommonOps_FDRM.identity(a.numRows)
-                    solver.solve(i, inverse)
-                    inverse.wrapMatrix()
-                }
-
-                override val determinant: Float by lazy { elementAlgebra.number(lu.computeDeterminant().real) }
+                override val u: Matrix<Float32>
+                    get() = lup.getUpper(null).wrapMatrix().withAttribute(UpperTriangular)
+                override val pivot: IntBuffer get() = lup.getRowPivotV(null).asBuffer()
             }
 
             else -> null
-        }?.let{
-            type.cast(it)
         }
+
+        @Suppress("UNCHECKED_CAST")
+        return raw as V?
     }
 
     /**
diff --git a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt
index e89810e0d..8b1b28e7d 100644
--- a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt
+++ b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -58,19 +58,19 @@ internal class EjmlMatrixTest {
 
     @OptIn(UnstableKMathAPI::class)
     @Test
-    fun features() {
+    fun features() = EjmlLinearSpaceDDRM {
         val m = randomMatrix
         val w = EjmlDoubleMatrix(m)
-        val det: DeterminantFeature<Double> = EjmlLinearSpaceDDRM.computeFeature(w) ?: fail()
-        assertEquals(CommonOps_DDRM.det(m), det.determinant)
-        val lup: LupDecompositionFeature<Double> = EjmlLinearSpaceDDRM.computeFeature(w) ?: fail()
+        val det: Double = w.getOrComputeAttribute(Determinant) ?: fail()
+        assertEquals(CommonOps_DDRM.det(m), det)
+        val lup: LupDecomposition<Double> = w.getOrComputeAttribute(LUP) ?: fail()
 
         val ludecompositionF64 = DecompositionFactory_DDRM.lu(m.numRows, m.numCols)
             .also { it.decompose(m.copy()) }
 
         assertMatrixEquals(EjmlDoubleMatrix(ludecompositionF64.getLower(null)), lup.l)
         assertMatrixEquals(EjmlDoubleMatrix(ludecompositionF64.getUpper(null)), lup.u)
-        assertMatrixEquals(EjmlDoubleMatrix(ludecompositionF64.getRowPivot(null)), lup.p)
+        assertMatrixEquals(EjmlDoubleMatrix(ludecompositionF64.getRowPivot(null)), lup.pivotMatrix(this))
     }
 
     @Test
@@ -96,7 +96,7 @@ internal class EjmlMatrixTest {
         val u = space.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
         val l = space.buildMatrix(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 }
         val matrix = space { l dot u }
-        val inverted = matrix.toEjml().inverse()
+        val inverted = matrix.toEjml().inverted()
 
         val res = matrix dot inverted
 
diff --git a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt
index 7d3ea314b..cbc7f7c41 100644
--- a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt
+++ b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-for-real/README.md b/kmath-for-real/README.md
index 638b15bfa..c65f6db46 100644
--- a/kmath-for-real/README.md
+++ b/kmath-for-real/README.md
@@ -9,19 +9,8 @@ Specialization of KMath APIs for Double numbers.
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-for-real:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-for-real:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-for-real:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -30,6 +19,6 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-for-real:0.4.0-dev-1")
+    implementation("space.kscience:kmath-for-real:0.4.0")
 }
 ```
diff --git a/kmath-for-real/build.gradle.kts b/kmath-for-real/build.gradle.kts
index 99ce5903f..a0426b516 100644
--- a/kmath-for-real/build.gradle.kts
+++ b/kmath-for-real/build.gradle.kts
@@ -6,6 +6,7 @@ kscience {
     jvm()
     js()
     native()
+    wasm()
 
     dependencies {
         api(projects.kmathCore)
diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt
index 411a35188..493a299c0 100644
--- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt
+++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,7 +7,7 @@ package space.kscience.kmath.real
 
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.linear.Point
-import space.kscience.kmath.operations.DoubleL2Norm
+import space.kscience.kmath.operations.Float64L2Norm
 import space.kscience.kmath.structures.Buffer
 import space.kscience.kmath.structures.MutableBuffer.Companion.double
 import space.kscience.kmath.structures.asBuffer
@@ -16,7 +16,6 @@ import kotlin.math.pow
 
 public typealias DoubleVector = Point<Double>
 
-@Suppress("FunctionName")
 public fun DoubleVector(vararg doubles: Double): DoubleVector = doubles.asBuffer()
 
 /**
@@ -103,4 +102,4 @@ public fun DoubleVector.sum(): Double {
     return res
 }
 
-public val DoubleVector.norm: Double get() = DoubleL2Norm.norm(this)
\ No newline at end of file
+public val DoubleVector.norm: Double get() = Float64L2Norm.norm(this)
\ No newline at end of file
diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt
index 40e4a91f1..208c82c6d 100644
--- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt
+++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -11,11 +11,11 @@ package space.kscience.kmath.real
 import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.linear.*
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.algebra
 import space.kscience.kmath.operations.asIterable
 import space.kscience.kmath.structures.Buffer
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import kotlin.math.pow
 
 /*
@@ -32,11 +32,11 @@ import kotlin.math.pow
 
 public typealias RealMatrix = Matrix<Double>
 
-public fun realMatrix(rowNum: Int, colNum: Int, initializer: DoubleField.(i: Int, j: Int) -> Double): RealMatrix =
+public fun realMatrix(rowNum: Int, colNum: Int, initializer: Float64Field.(i: Int, j: Int) -> Double): RealMatrix =
     Double.algebra.linearSpace.buildMatrix(rowNum, colNum, initializer)
 
 @OptIn(UnstableKMathAPI::class)
-public fun realMatrix(rowNum: Int, colNum: Int): MatrixBuilder<Double, DoubleField> =
+public fun realMatrix(rowNum: Int, colNum: Int): MatrixBuilder<Double, Float64Field> =
     Double.algebra.linearSpace.matrix(rowNum, colNum)
 
 public fun Array<DoubleArray>.toMatrix(): RealMatrix {
@@ -130,19 +130,19 @@ public fun RealMatrix.extractColumns(columnRange: IntRange): RealMatrix =
 public fun RealMatrix.extractColumn(columnIndex: Int): RealMatrix =
     extractColumns(columnIndex..columnIndex)
 
-public fun RealMatrix.sumByColumn(): DoubleBuffer = DoubleBuffer(colNum) { j ->
+public fun RealMatrix.sumByColumn(): Float64Buffer = Float64Buffer(colNum) { j ->
     columns[j].sum()
 }
 
-public fun RealMatrix.minByColumn(): DoubleBuffer = DoubleBuffer(colNum) { j ->
+public fun RealMatrix.minByColumn(): Float64Buffer = Float64Buffer(colNum) { j ->
     columns[j].asIterable().minOrNull() ?: error("Cannot produce min on empty column")
 }
 
-public fun RealMatrix.maxByColumn(): DoubleBuffer = DoubleBuffer(colNum) { j ->
+public fun RealMatrix.maxByColumn(): Float64Buffer = Float64Buffer(colNum) { j ->
     columns[j].asIterable().maxOrNull() ?: error("Cannot produce min on empty column")
 }
 
-public fun RealMatrix.averageByColumn(): DoubleBuffer = DoubleBuffer(colNum) { j ->
+public fun RealMatrix.averageByColumn(): Float64Buffer = Float64Buffer(colNum) { j ->
     columns[j].asIterable().average()
 }
 
diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt
index 0c18602f1..e9fdfb506 100644
--- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt
+++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt
index adb62b173..3a25739c3 100644
--- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt
+++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,7 +7,7 @@ package space.kscience.kmath.real
 
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.structures.Buffer
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import kotlin.math.floor
 
 public val ClosedFloatingPointRange<Double>.length: Double get() = endInclusive - start
@@ -16,30 +16,30 @@ public val ClosedFloatingPointRange<Double>.length: Double get() = endInclusive
  * Create a Buffer-based grid with equally distributed [numberOfPoints] points. The range could be increasing or  decreasing.
  * If range has a zero size, then the buffer consisting of [numberOfPoints] equal values is returned.
  */
-public fun Buffer.Companion.fromRange(range: ClosedFloatingPointRange<Double>, numberOfPoints: Int): DoubleBuffer {
+public fun Buffer.Companion.fromRange(range: ClosedFloatingPointRange<Double>, numberOfPoints: Int): Float64Buffer {
     require(numberOfPoints >= 2) { "Number of points in grid must be more than 1" }
     val normalizedRange = when {
         range.endInclusive > range.start -> range
         range.endInclusive < range.start -> range.endInclusive..range.start
-        else -> return DoubleBuffer(numberOfPoints) { range.start }
+        else -> return Float64Buffer(numberOfPoints) { range.start }
     }
     val step = normalizedRange.length / (numberOfPoints - 1)
-    return DoubleBuffer(numberOfPoints) { normalizedRange.start + step * it }
+    return Float64Buffer(numberOfPoints) { normalizedRange.start + step * it }
 }
 
 /**
  * Create a Buffer-based grid with equally distributed points with a fixed [step]. The range could be increasing or  decreasing.
  * If the step is larger than the range size, single point is returned.
  */
-public fun Buffer.Companion.withFixedStep(range: ClosedFloatingPointRange<Double>, step: Double): DoubleBuffer {
+public fun Buffer.Companion.withFixedStep(range: ClosedFloatingPointRange<Double>, step: Double): Float64Buffer {
     require(step > 0) { "The grid step must be positive" }
     val normalizedRange = when {
         range.endInclusive > range.start -> range
         range.endInclusive < range.start -> range.endInclusive..range.start
-        else -> return DoubleBuffer(range.start)
+        else -> return Float64Buffer(range.start)
     }
     val numberOfPoints = floor(normalizedRange.length / step).toInt() + 1
-    return DoubleBuffer(numberOfPoints) { normalizedRange.start + step * it  }
+    return Float64Buffer(numberOfPoints) { normalizedRange.start + step * it }
 }
 
 /**
@@ -51,4 +51,4 @@ public fun Buffer.Companion.withFixedStep(range: ClosedFloatingPointRange<Double
  * If step is negative, the same goes from upper boundary downwards
  */
 @UnstableKMathAPI
-public infix fun ClosedFloatingPointRange<Double>.step(step: Double): DoubleBuffer = Buffer.withFixedStep(this, step)
\ No newline at end of file
+public infix fun ClosedFloatingPointRange<Double>.step(step: Double): Float64Buffer = Buffer.withFixedStep(this, step)
\ No newline at end of file
diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt
index 2c06b76b7..223cdd25d 100644
--- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt
+++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt
@@ -1,20 +1,20 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.real
 
 import space.kscience.kmath.nd.BufferND
-import space.kscience.kmath.operations.DoubleField
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.operations.Float64Field
+import space.kscience.kmath.structures.Float64Buffer
 
 /**
  * Map one [BufferND] using function without indices.
  */
-public inline fun BufferND<Double>.mapInline(crossinline transform: DoubleField.(Double) -> Double): BufferND<Double> {
-    val array = DoubleArray(indices.linearSize) { offset -> DoubleField.transform(buffer[offset]) }
-    return BufferND(indices, DoubleBuffer(array))
+public inline fun BufferND<Double>.mapInline(crossinline transform: Float64Field.(Double) -> Double): BufferND<Double> {
+    val array = DoubleArray(indices.linearSize) { offset -> Float64Field.transform(buffer[offset]) }
+    return BufferND(indices, Float64Buffer(array))
 }
 
 /**
diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt
index c00cd84d1..f54ec6290 100644
--- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt
+++ b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt
index a25091ac2..d4051c8d9 100644
--- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt
+++ b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,34 +7,34 @@ package space.kscience.kmath.real
 
 import space.kscience.kmath.linear.asMatrix
 import space.kscience.kmath.linear.linearSpace
-import space.kscience.kmath.linear.transpose
+import space.kscience.kmath.linear.transposed
 import space.kscience.kmath.operations.algebra
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import kotlin.test.Test
 import kotlin.test.assertEquals
 
 internal class DoubleVectorTest {
     @Test
     fun testSum() {
-        val vector1 = DoubleBuffer(5) { it.toDouble() }
-        val vector2 = DoubleBuffer(5) { 5 - it.toDouble() }
+        val vector1 = Float64Buffer(5) { it.toDouble() }
+        val vector2 = Float64Buffer(5) { 5 - it.toDouble() }
         val sum = vector1 + vector2
         assertEquals(5.0, sum[2])
     }
 
     @Test
     fun testVectorToMatrix() {
-        val vector = DoubleBuffer(5) { it.toDouble() }
+        val vector = Float64Buffer(5) { it.toDouble() }
         val matrix = vector.asMatrix()
         assertEquals(4.0, matrix[4, 0])
     }
 
     @Test
     fun testDot() = Double.algebra.linearSpace.run {
-        val vector1 = DoubleBuffer(5) { it.toDouble() }
-        val vector2 = DoubleBuffer(5) { 5 - it.toDouble() }
+        val vector1 = Float64Buffer(5) { it.toDouble() }
+        val vector2 = Float64Buffer(5) { 5 - it.toDouble() }
         val matrix1 = vector1.asMatrix()
-        val matrix2 = vector2.asMatrix().transpose()
+        val matrix2 = vector2.asMatrix().transposed()
         val product = matrix1 dot matrix2
         assertEquals(5.0, product[1, 0])
         assertEquals(6.0, product[2, 2])
diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt
index 35c53f9d6..035eccb9e 100644
--- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt
+++ b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -20,9 +20,9 @@ class GridTest {
     }
 
     @Test
-    fun testIterateGrid(){
+    fun testIterateGrid() {
         var res = 0.0
-        for(d in 0.0..1.0 step 0.2){
+        for (d in 0.0..1.0 step 0.2) {
             res = d
         }
         assertEquals(1.0, res)
diff --git a/kmath-functions/README.md b/kmath-functions/README.md
index 929fd9172..c53bc5c11 100644
--- a/kmath-functions/README.md
+++ b/kmath-functions/README.md
@@ -11,19 +11,8 @@ Functions and interpolations.
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-functions:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-functions:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-functions:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -32,6 +21,6 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-functions:0.4.0-dev-1")
+    implementation("space.kscience:kmath-functions:0.4.0")
 }
 ```
diff --git a/kmath-functions/build.gradle.kts b/kmath-functions/build.gradle.kts
index acabd1eb9..e7fcab84a 100644
--- a/kmath-functions/build.gradle.kts
+++ b/kmath-functions/build.gradle.kts
@@ -2,28 +2,11 @@ plugins {
     id("space.kscience.gradle.mpp")
 }
 
-kscience{
+kscience {
     jvm()
     js()
     native()
-
-    wasm{
-        browser {
-            testTask {
-                useKarma {
-                    this.webpackConfig.experiments.add("topLevelAwait")
-                    useChromeHeadless()
-                    useConfigDirectory(project.projectDir.resolve("karma.config.d").resolve("wasm"))
-                }
-            }
-        }
-    }
-
-    wasmTest{
-        dependencies {
-            implementation(kotlin("test"))
-        }
-    }
+    wasm()
 
     dependencies {
         api(projects.kmathCore)
diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt
index a9e75e456..8c02ee044 100644
--- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt
+++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt
index af84f47f2..35a947700 100644
--- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt
+++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -10,6 +10,7 @@ package space.kscience.kmath.functions
 import space.kscience.kmath.operations.Ring
 import space.kscience.kmath.operations.ScaleOperations
 import space.kscience.kmath.operations.invoke
+import space.kscience.kmath.structures.MutableBufferFactory
 import kotlin.math.max
 import kotlin.math.min
 
@@ -48,7 +49,7 @@ public data class Polynomial<out C>(
      *
      * @usesMathJax
      */
-    public val coefficients: List<C>
+    public val coefficients: List<C>,
 ) {
     override fun toString(): String = "Polynomial$coefficients"
 }
@@ -62,16 +63,15 @@ public data class Polynomial<out C>(
  * @param ring underlying ring of constants of type [A].
  */
 public open class PolynomialSpace<C, A>(
-    /**
-     * Underlying ring of constants. Its operations on constants are used by local operations on constants and polynomials.
-     */
     public val ring: A,
 ) : Ring<Polynomial<C>>, ScaleOperations<Polynomial<C>> where A : Ring<C>, A : ScaleOperations<C> {
+    override val bufferFactory: MutableBufferFactory<Polynomial<C>> get() = MutableBufferFactory()
 
     /**
      * Instance of zero constant (zero of the underlying ring).
      */
     public val constantZero: C get() = ring.zero
+
     /**
      * Instance of unit constant (unit of the underlying ring).
      */
@@ -95,6 +95,7 @@ public open class PolynomialSpace<C, A>(
                 )
             }
         }
+
     /**
      * Returns difference between the constant represented as a polynomial and the polynomial.
      */
@@ -115,6 +116,7 @@ public open class PolynomialSpace<C, A>(
                 )
             }
         }
+
     /**
      * Returns product of the constant represented as a polynomial and the polynomial.
      */
@@ -147,6 +149,7 @@ public open class PolynomialSpace<C, A>(
                 )
             }
         }
+
     /**
      * Returns difference between the constant represented as a polynomial and the polynomial.
      */
@@ -165,6 +168,7 @@ public open class PolynomialSpace<C, A>(
                 )
             }
         }
+
     /**
      * Returns product of the constant represented as a polynomial and the polynomial.
      */
@@ -183,6 +187,7 @@ public open class PolynomialSpace<C, A>(
      * Converts the constant [value] to polynomial.
      */
     public fun number(value: C): Polynomial<C> = Polynomial(listOf(value))
+
     /**
      * Converts the constant to polynomial.
      */
@@ -194,6 +199,7 @@ public open class PolynomialSpace<C, A>(
     public override operator fun Polynomial<C>.unaryMinus(): Polynomial<C> = ring {
         Polynomial(coefficients.map { -it })
     }
+
     /**
      * Returns sum of the polynomials.
      */
@@ -210,6 +216,7 @@ public open class PolynomialSpace<C, A>(
             }
         )
     }
+
     /**
      * Returns difference of the polynomials.
      */
@@ -226,6 +233,7 @@ public open class PolynomialSpace<C, A>(
             }
         )
     }
+
     /**
      * Returns product of the polynomials.
      */
@@ -245,6 +253,7 @@ public open class PolynomialSpace<C, A>(
      * Instance of zero polynomial (zero of the polynomial ring).
      */
     override val zero: Polynomial<C> = Polynomial(emptyList())
+
     /**
      * Instance of unit polynomial (unit of the polynomial ring).
      */
diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt
index c2f95f040..6f2ba6c75 100644
--- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt
+++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt
index 4e9791a87..dceef2b75 100644
--- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt
+++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -20,9 +20,4 @@ public fun <C> Polynomial(coefficients: List<C>, reverse: Boolean = false): Poly
  */
 @Suppress("FunctionName")
 public fun <C> Polynomial(vararg coefficients: C, reverse: Boolean = false): Polynomial<C> =
-    Polynomial(with(coefficients) { if (reverse) reversed() else toList() })
-
-/**
- * Represents [this] constant as a [Polynomial].
- */
-public fun <C> C.asPolynomial() : Polynomial<C> = Polynomial(listOf(this))
\ No newline at end of file
+    Polynomial(with(coefficients) { if (reverse) reversed() else toList() })
\ No newline at end of file
diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt
index 0d4b93f03..e85f698c4 100644
--- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt
+++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -64,7 +64,7 @@ public fun <C, A> Polynomial<C>.differentiate(
 ): Polynomial<C> where  A : Ring<C>, A : NumericAlgebra<C> = ring {
     Polynomial(
         buildList(max(0, coefficients.size - 1)) {
-            for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg])
+            for (deg in 1..coefficients.lastIndex) add(number(deg) * coefficients[deg])
         }
     )
 }
diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt
index f2ac0a296..666379c7a 100644
--- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt
+++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt
@@ -1,9 +1,10 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 package space.kscience.kmath.integration
 
+import space.kscience.attributes.AttributesBuilder
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.operations.Field
 import space.kscience.kmath.structures.Buffer
@@ -11,14 +12,14 @@ import space.kscience.kmath.structures.asBuffer
 import space.kscience.kmath.structures.indices
 
 /**
- * A simple one-pass integrator based on Gauss rule
- * Following integrand features are accepted:
+ * A simple one-pass integrator based on Gauss rule.
+ * The following integrand features are accepted:
  *
  * * [GaussIntegratorRuleFactory]&mdash;a factory for computing the Gauss integration rule. By default, uses
  * [GaussLegendreRuleFactory].
  * * [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.
+ * use 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].
  */
@@ -27,11 +28,11 @@ public class GaussIntegrator<T : Any>(
 ) : UnivariateIntegrator<T> {
 
     private fun buildRule(integrand: UnivariateIntegrand<T>): Pair<Buffer<Double>, Buffer<Double>> {
-        val factory = integrand.getFeature<GaussIntegratorRuleFactory>() ?: GaussLegendreRuleFactory
-        val predefinedRanges = integrand.getFeature<UnivariateIntegrandRanges>()
+        val factory = integrand[GaussIntegratorRuleFactory] ?: GaussLegendreRuleFactory
+        val predefinedRanges = integrand[UnivariateIntegrandRanges]
         if (predefinedRanges == null || predefinedRanges.ranges.isEmpty()) {
-            val numPoints = integrand.getFeature<IntegrandMaxCalls>()?.maxCalls ?: 100
-            val range = integrand.getFeature<IntegrationRange>()?.range ?: 0.0..1.0
+            val numPoints = integrand[IntegrandMaxCalls] ?: 100
+            val range = integrand[IntegrationRange] ?: 0.0..1.0
             return factory.build(numPoints, range)
         } else {
             val ranges = predefinedRanges.ranges
@@ -53,10 +54,10 @@ public class GaussIntegrator<T : Any>(
         }
     }
 
-    override fun process(integrand: UnivariateIntegrand<T>): UnivariateIntegrand<T> = with(algebra) {
+    override fun integrate(integrand: UnivariateIntegrand<T>): UnivariateIntegrand<T> = with(algebra) {
         val f = integrand.function
         val (points, weights) = buildRule(integrand)
-        var res = zero
+        var res: T = zero
         var c = zero
         for (i in points.indices) {
             val x = points[i]
@@ -66,7 +67,10 @@ public class GaussIntegrator<T : Any>(
             c = t - res - y
             res = t
         }
-        return integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + points.size)
+        return integrand.withAttributes {
+            IntegrandValue(res)
+            IntegrandCallsPerformed(integrand.calls + points.size)
+        }
     }
 
     public companion object
@@ -84,12 +88,12 @@ public val <T : Any> Field<T>.gaussIntegrator: GaussIntegrator<T> get() = GaussI
  * Integrate using [intervals] segments with Gauss-Legendre rule of [order] order.
  */
 @UnstableKMathAPI
-public fun <T : Any> GaussIntegrator<T>.integrate(
+public inline fun <reified T : Any> GaussIntegrator<T>.integrate(
     range: ClosedRange<Double>,
     order: Int = 10,
     intervals: Int = 10,
-    vararg features: IntegrandFeature,
-    function: (Double) -> T,
+    noinline attributesBuilder: AttributesBuilder<UnivariateIntegrand<T>>.() -> Unit = {},
+    noinline function: (Double) -> T,
 ): UnivariateIntegrand<T> {
     require(range.endInclusive > range.start) { "The range upper bound should be higher than lower bound" }
     require(order > 1) { "The order of polynomial must be more than 1" }
@@ -98,13 +102,15 @@ public fun <T : Any> GaussIntegrator<T>.integrate(
     val ranges = UnivariateIntegrandRanges(
         (0 until intervals).map { i -> (range.start + rangeSize * i)..(range.start + rangeSize * (i + 1)) to order }
     )
-    return process(
-        UnivariateIntegrand(
-            function,
-            IntegrationRange(range),
-            GaussLegendreRuleFactory,
-            ranges,
-            *features
+    return integrate(
+        UnivariateIntegrand<T>(
+            attributeBuilder = {
+                IntegrationRange(range)
+                GaussIntegratorRuleFactory(GaussLegendreRuleFactory)
+                UnivariateIntegrandRanges(ranges)
+                attributesBuilder()
+            },
+            function = function,
         )
     )
 }
\ No newline at end of file
diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt
index 4ed4965c9..60777bfdb 100644
--- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt
+++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt
@@ -1,21 +1,22 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.integration
 
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.mapToBuffer
 import space.kscience.kmath.structures.Buffer
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import space.kscience.kmath.structures.asBuffer
 import kotlin.math.ulp
 import kotlin.native.concurrent.ThreadLocal
 
-public interface GaussIntegratorRuleFactory : IntegrandFeature {
+public interface GaussIntegratorRuleFactory {
     public fun build(numPoints: Int): Pair<Buffer<Double>, Buffer<Double>>
 
-    public companion object {
+    public companion object : IntegrandAttribute<GaussIntegratorRuleFactory> {
         public fun double(numPoints: Int, range: ClosedRange<Double>): Pair<Buffer<Double>, Buffer<Double>> =
             GaussLegendreRuleFactory.build(numPoints, range)
     }
@@ -32,11 +33,11 @@ public fun GaussIntegratorRuleFactory.build(
     val normalized: Pair<Buffer<Double>, Buffer<Double>> = build(numPoints)
     val length = range.endInclusive - range.start
 
-    val points = normalized.first.mapToBuffer(::DoubleBuffer) {
+    val points = normalized.first.mapToBuffer(Float64Field.bufferFactory) {
         range.start + length / 2 + length / 2 * it
     }
 
-    val weights = normalized.second.mapToBuffer(::DoubleBuffer) {
+    val weights = normalized.second.mapToBuffer(Float64Field.bufferFactory) {
         it * length / 2
     }
 
@@ -64,8 +65,8 @@ public object GaussLegendreRuleFactory : GaussIntegratorRuleFactory {
         if (numPoints == 1) {
             // Break recursion.
             return Pair(
-                DoubleBuffer(0.0),
-                DoubleBuffer(0.0)
+                Float64Buffer(0.0),
+                Float64Buffer(0.0)
             )
         }
 
diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt
index 40fe78898..babc86c54 100644
--- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt
+++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt
@@ -1,48 +1,57 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.integration
 
-import space.kscience.kmath.misc.Feature
-import space.kscience.kmath.misc.FeatureSet
-import space.kscience.kmath.misc.Featured
-import kotlin.reflect.KClass
+import space.kscience.attributes.*
 
-public interface IntegrandFeature : Feature<IntegrandFeature> {
-    override fun toString(): String
+public interface IntegrandAttribute<T> : Attribute<T>
+
+public interface Integrand<T> : AttributeContainer {
+
+    public val type: SafeType<T>
+
+    /**
+     * Create a copy of this integrand with a new set of attributes
+     */
+    public fun withAttributes(attributes: Attributes): Integrand<T>
+
+    public companion object
 }
 
-public interface Integrand : Featured<IntegrandFeature> {
-    public val features: FeatureSet<IntegrandFeature>
-    override fun <T : IntegrandFeature> getFeature(type: KClass<out T>): T? = features.getFeature(type)
+public operator fun <T> Integrand<*>.get(attribute: Attribute<T>): T? = attributes[attribute]
+
+public sealed class IntegrandValue<T> private constructor() : IntegrandAttribute<T> {
+    public companion object : IntegrandValue<Any?>() {
+        @Suppress("UNCHECKED_CAST")
+        public fun <T> forType(): IntegrandValue<T> = this as IntegrandValue<T>
+    }
 }
 
-public inline fun <reified T : IntegrandFeature> Integrand.getFeature(): T? = getFeature(T::class)
-
-public class IntegrandValue<out T : Any>(public val value: T) : IntegrandFeature {
-    override fun toString(): String = "Value($value)"
+public fun <T> AttributesBuilder<Integrand<T>>.value(value: T) {
+    IntegrandValue.forType<T>().invoke(value)
 }
 
-public class IntegrandRelativeAccuracy(public val accuracy: Double) : IntegrandFeature {
-    override fun toString(): String = "TargetRelativeAccuracy($accuracy)"
-}
+/**
+ * Value of the integrand if it is present or null
+ */
+public inline val <reified T : Any> Integrand<T>.valueOrNull: T? get() = attributes[IntegrandValue.forType<T>()]
 
-public class IntegrandAbsoluteAccuracy(public val accuracy: Double) : IntegrandFeature {
-    override fun toString(): String = "TargetAbsoluteAccuracy($accuracy)"
-}
+/**
+ * Value of the integrand or error
+ */
+public inline val <reified T : Any> Integrand<T>.value: T get() = valueOrNull ?: error("No value in the integrand")
 
-public class IntegrandCallsPerformed(public val calls: Int) : IntegrandFeature {
-    override fun toString(): String = "Calls($calls)"
-}
+public object IntegrandRelativeAccuracy : IntegrandAttribute<Double>
 
-public val Integrand.calls: Int get() = getFeature<IntegrandCallsPerformed>()?.calls ?: 0
+public object IntegrandAbsoluteAccuracy : IntegrandAttribute<Double>
 
-public class IntegrandMaxCalls(public val maxCalls: Int) : IntegrandFeature {
-    override fun toString(): String = "MaxCalls($maxCalls)"
-}
+public object IntegrandCallsPerformed : IntegrandAttribute<Int>
 
-public class IntegrandIterationsRange(public val range: IntRange) : IntegrandFeature {
-    override fun toString(): String = "Iterations(${range.first}..${range.last})"
-}
+public val Integrand<*>.calls: Int get() = attributes[IntegrandCallsPerformed] ?: 0
+
+public object IntegrandMaxCalls : IntegrandAttribute<Int>
+
+public object IntegrandIterationsRange : IntegrandAttribute<IntRange>
diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt
index 18c46b83b..cc8b833bd 100644
--- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt
+++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,9 +8,9 @@ package space.kscience.kmath.integration
 /**
  * A general interface for all integrators.
  */
-public interface Integrator<I : Integrand> {
+public interface Integrator<T, I : Integrand<T>> {
     /**
      * Runs one integration pass and return a new [Integrand] with a new set of features.
      */
-    public fun process(integrand: I): I
+    public fun integrate(integrand: I): I
 }
diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt
index 53a563086..79e867576 100644
--- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt
+++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt
@@ -1,26 +1,34 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.integration
 
+import space.kscience.attributes.*
 import space.kscience.kmath.linear.Point
-import space.kscience.kmath.misc.FeatureSet
 
-public class MultivariateIntegrand<T : Any> internal constructor(
-    override val features: FeatureSet<IntegrandFeature>,
+public class MultivariateIntegrand<T>(
+    override val type: SafeType<T>,
+    override val attributes: Attributes,
     public val function: (Point<T>) -> T,
-) : Integrand {
+) : Integrand<T> {
+
+    override fun withAttributes(attributes: Attributes): MultivariateIntegrand<T> =
+        MultivariateIntegrand(type, attributes, function)
 
-    public operator fun <F : IntegrandFeature> plus(feature: F): MultivariateIntegrand<T> =
-        MultivariateIntegrand(features.with(feature), function)
 }
 
-@Suppress("FunctionName")
-public fun <T : Any> MultivariateIntegrand(
-    vararg features: IntegrandFeature,
-    function: (Point<T>) -> T,
-): MultivariateIntegrand<T> = MultivariateIntegrand(FeatureSet.of(*features), function)
+public fun <T, A : Any> MultivariateIntegrand<T>.withAttribute(
+    attribute: Attribute<A>,
+    value: A,
+): MultivariateIntegrand<T> = withAttributes(attributes.withAttribute(attribute, value))
 
-public val <T : Any> MultivariateIntegrand<T>.value: T? get() = getFeature<IntegrandValue<T>>()?.value
+public fun <T> MultivariateIntegrand<T>.withAttributes(
+    block: AttributesBuilder<MultivariateIntegrand<T>>.() -> Unit,
+): MultivariateIntegrand<T> = withAttributes(attributes.modified(block))
+
+public inline fun <reified T : Any> MultivariateIntegrand(
+    noinline attributeBuilder: AttributesBuilder<MultivariateIntegrand<T>>.() -> Unit,
+    noinline function: (Point<T>) -> T,
+): MultivariateIntegrand<T> = MultivariateIntegrand(safeTypeOf<T>(), Attributes(attributeBuilder), function)
diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt
index 73a3cc25b..60e53c54a 100644
--- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt
+++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt
@@ -1,13 +1,13 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.integration
 
 import space.kscience.kmath.UnstableKMathAPI
-import space.kscience.kmath.operations.DoubleField
 import space.kscience.kmath.operations.Field
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.invoke
 import space.kscience.kmath.operations.sum
 
@@ -44,17 +44,23 @@ public class SimpsonIntegrator<T : Any>(
         return res
     }
 
-    override fun process(integrand: UnivariateIntegrand<T>): UnivariateIntegrand<T> {
-        val ranges = integrand.getFeature<UnivariateIntegrandRanges>()
+    override fun integrate(integrand: UnivariateIntegrand<T>): UnivariateIntegrand<T> {
+        val ranges = integrand[UnivariateIntegrandRanges]
         return if (ranges != null) {
             val res = algebra.sum(ranges.ranges.map { integrateRange(integrand, it.first, it.second) })
-            integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + ranges.ranges.sumOf { it.second })
+            integrand.withAttributes {
+                IntegrandValue(res)
+                IntegrandCallsPerformed(integrand.calls + ranges.ranges.sumOf { it.second })
+            }
         } else {
-            val numPoints = integrand.getFeature<IntegrandMaxCalls>()?.maxCalls ?: 100
+            val numPoints = integrand[IntegrandMaxCalls] ?: 100
             require(numPoints >= 4) { "Simpson integrator requires at least 4 nodes" }
-            val range = integrand.getFeature<IntegrationRange>()?.range ?: 0.0..1.0
+            val range = integrand[IntegrationRange] ?: 0.0..1.0
             val res = integrateRange(integrand, range, numPoints)
-            integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + numPoints)
+            integrand.withAttributes {
+                IntegrandValue(res)
+                IntegrandCallsPerformed(integrand.calls + numPoints)
+            }
         }
     }
 }
@@ -90,19 +96,25 @@ public object DoubleSimpsonIntegrator : UnivariateIntegrator<Double> {
         return res
     }
 
-    override fun process(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
-        val ranges = integrand.getFeature<UnivariateIntegrandRanges>()
+    override fun integrate(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
+        val ranges = integrand[UnivariateIntegrandRanges]
         return if (ranges != null) {
             val res = ranges.ranges.sumOf { integrateRange(integrand, it.first, it.second) }
-            integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + ranges.ranges.sumOf { it.second })
+            integrand.withAttributes {
+                IntegrandValue(res)
+                IntegrandCallsPerformed(integrand.calls + ranges.ranges.sumOf { it.second })
+            }
         } else {
-            val numPoints = integrand.getFeature<IntegrandMaxCalls>()?.maxCalls ?: 100
+            val numPoints = integrand[IntegrandMaxCalls] ?: 100
             require(numPoints >= 4) { "Simpson integrator requires at least 4 nodes" }
-            val range = integrand.getFeature<IntegrationRange>()?.range ?: 0.0..1.0
+            val range = integrand[IntegrationRange] ?: 0.0..1.0
             val res = integrateRange(integrand, range, numPoints)
-            integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + numPoints)
+            integrand.withAttributes {
+                IntegrandValue(res)
+                IntegrandCallsPerformed(integrand.calls + numPoints)
+            }
         }
     }
 }
 
-public val DoubleField.simpsonIntegrator: DoubleSimpsonIntegrator get() = DoubleSimpsonIntegrator
\ No newline at end of file
+public val Float64Field.simpsonIntegrator: DoubleSimpsonIntegrator get() = DoubleSimpsonIntegrator
\ No newline at end of file
diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt
index 993812b29..24149959b 100644
--- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt
+++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -14,7 +14,7 @@ import space.kscience.kmath.interpolation.SplineInterpolator
 import space.kscience.kmath.interpolation.interpolatePolynomials
 import space.kscience.kmath.operations.*
 import space.kscience.kmath.structures.Buffer
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import space.kscience.kmath.structures.MutableBufferFactory
 
 /**
@@ -54,15 +54,15 @@ public class SplineIntegrator<T : Comparable<T>>(
     public val algebra: Field<T>,
     public val bufferFactory: MutableBufferFactory<T>,
 ) : UnivariateIntegrator<T> {
-    override fun process(integrand: UnivariateIntegrand<T>): UnivariateIntegrand<T> = algebra {
-        val range = integrand.getFeature<IntegrationRange>()?.range ?: 0.0..1.0
+    override fun integrate(integrand: UnivariateIntegrand<T>): UnivariateIntegrand<T> = algebra {
+        val range = integrand[IntegrationRange] ?: 0.0..1.0
 
         val interpolator: PolynomialInterpolator<T> = SplineInterpolator(algebra, bufferFactory)
 
-        val nodes: Buffer<Double> = integrand.getFeature<UnivariateIntegrationNodes>()?.nodes ?: run {
-            val numPoints = integrand.getFeature<IntegrandMaxCalls>()?.maxCalls ?: 100
+        val nodes: Buffer<Double> = integrand[UnivariateIntegrationNodes] ?: run {
+            val numPoints = integrand[IntegrandMaxCalls] ?: 100
             val step = (range.endInclusive - range.start) / (numPoints - 1)
-            DoubleBuffer(numPoints) { i -> range.start + i * step }
+            Float64Buffer(numPoints) { i -> range.start + i * step }
         }
 
         val values = nodes.mapToBuffer(bufferFactory) { integrand.function(it) }
@@ -71,7 +71,10 @@ public class SplineIntegrator<T : Comparable<T>>(
             values
         )
         val res = polynomials.integrate(algebra, number(range.start)..number(range.endInclusive))
-        integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + nodes.size)
+        integrand.withAttributes {
+            IntegrandValue(res)
+            IntegrandCallsPerformed(integrand.calls + nodes.size)
+        }
     }
 }
 
@@ -83,24 +86,27 @@ public class SplineIntegrator<T : Comparable<T>>(
  */
 @UnstableKMathAPI
 public object DoubleSplineIntegrator : UnivariateIntegrator<Double> {
-    override fun process(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
-        val range = integrand.getFeature<IntegrationRange>()?.range ?: 0.0..1.0
-        val interpolator: PolynomialInterpolator<Double> = SplineInterpolator(DoubleField, ::DoubleBuffer)
+    override fun integrate(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
+        val range = integrand[IntegrationRange] ?: 0.0..1.0
+        val interpolator: PolynomialInterpolator<Double> = SplineInterpolator(Float64Field, Float64Field.bufferFactory)
 
-        val nodes: Buffer<Double> = integrand.getFeature<UnivariateIntegrationNodes>()?.nodes ?: run {
-            val numPoints = integrand.getFeature<IntegrandMaxCalls>()?.maxCalls ?: 100
+        val nodes: Buffer<Double> = integrand[UnivariateIntegrationNodes] ?: run {
+            val numPoints = integrand[IntegrandMaxCalls] ?: 100
             val step = (range.endInclusive - range.start) / (numPoints - 1)
-            DoubleBuffer(numPoints) { i -> range.start + i * step }
+            Float64Buffer(numPoints) { i -> range.start + i * step }
         }
 
-        val values = nodes.mapToBuffer(::DoubleBuffer) { integrand.function(it) }
+        val values = nodes.mapToBuffer(Float64Field.bufferFactory) { integrand.function(it) }
         val polynomials = interpolator.interpolatePolynomials(nodes, values)
-        val res = polynomials.integrate(DoubleField, range)
-        return integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + nodes.size)
+        val res = polynomials.integrate(Float64Field, range)
+        return integrand.withAttributes {
+            IntegrandValue(res)
+            IntegrandCallsPerformed(integrand.calls + nodes.size)
+        }
     }
 }
 
 @Suppress("unused")
 @UnstableKMathAPI
-public inline val DoubleField.splineIntegrator: UnivariateIntegrator<Double>
+public inline val Float64Field.splineIntegrator: UnivariateIntegrator<Double>
     get() = DoubleSplineIntegrator
\ No newline at end of file
diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt
index f18e86b80..e5d220f0f 100644
--- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt
+++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt
@@ -1,40 +1,49 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.integration
 
+import space.kscience.attributes.*
 import space.kscience.kmath.UnstableKMathAPI
-import space.kscience.kmath.misc.FeatureSet
 import space.kscience.kmath.structures.Buffer
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 
-public class UnivariateIntegrand<T> internal constructor(
-    override val features: FeatureSet<IntegrandFeature>,
+public class UnivariateIntegrand<T>(
+    override val type: SafeType<T>,
+    override val attributes: Attributes,
     public val function: (Double) -> T,
-) : Integrand {
-    public operator fun <F : IntegrandFeature> plus(feature: F): UnivariateIntegrand<T> =
-        UnivariateIntegrand(features.with(feature), function)
+) : Integrand<T> {
+
+    override fun withAttributes(attributes: Attributes): UnivariateIntegrand<T> =
+        UnivariateIntegrand(type, attributes, function)
 }
 
-@Suppress("FunctionName")
-public fun <T : Any> UnivariateIntegrand(
-    function: (Double) -> T,
-    vararg features: IntegrandFeature,
-): UnivariateIntegrand<T> = UnivariateIntegrand(FeatureSet.of(*features), function)
+public fun <T, A : Any> UnivariateIntegrand<T>.withAttribute(
+    attribute: Attribute<A>,
+    value: A,
+): UnivariateIntegrand<T> = withAttributes(attributes.withAttribute(attribute, value))
 
-public typealias UnivariateIntegrator<T> = Integrator<UnivariateIntegrand<T>>
+public fun <T> UnivariateIntegrand<T>.withAttributes(
+    block: AttributesBuilder<UnivariateIntegrand<T>>.() -> Unit,
+): UnivariateIntegrand<T> = withAttributes(attributes.modified(block))
+
+public inline fun <reified T : Any> UnivariateIntegrand(
+    noinline attributeBuilder: AttributesBuilder<UnivariateIntegrand<T>>.() -> Unit,
+    noinline function: (Double) -> T,
+): UnivariateIntegrand<T> = UnivariateIntegrand(safeTypeOf(), Attributes(attributeBuilder), function)
+
+public typealias UnivariateIntegrator<T> = Integrator<T, UnivariateIntegrand<T>>
+
+public object IntegrationRange : IntegrandAttribute<ClosedRange<Double>>
 
-public class IntegrationRange(public val range: ClosedRange<Double>) : IntegrandFeature {
-    override fun toString(): String = "Range(${range.start}..${range.endInclusive})"
-}
 
 /**
  * Set of univariate integration ranges. First components correspond to the ranges themselves, second components to
- * number of integration nodes per range.
+ * the 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>>) {
     public constructor(vararg pairs: Pair<ClosedRange<Double>, Int>) : this(pairs.toList())
 
     override fun toString(): String {
@@ -43,60 +52,44 @@ public class UnivariateIntegrandRanges(public val ranges: List<Pair<ClosedRange<
         }
         return "UnivariateRanges($rangesString)"
     }
+
+    public companion object : IntegrandAttribute<UnivariateIntegrandRanges>
 }
 
-public class UnivariateIntegrationNodes(public val nodes: Buffer<Double>) : IntegrandFeature {
-    public constructor(vararg nodes: Double) : this(DoubleBuffer(nodes))
+public object UnivariateIntegrationNodes : IntegrandAttribute<Buffer<Double>>
 
-    override fun toString(): String = "UnivariateNodes($nodes)"
+public fun AttributesBuilder<UnivariateIntegrand<*>>.integrationNodes(vararg nodes: Double) {
+    UnivariateIntegrationNodes(Float64Buffer(nodes))
 }
 
-
-/**
- * Value of the integrand if it is present or null
- */
-public val <T : Any> UnivariateIntegrand<T>.valueOrNull: T? get() = getFeature<IntegrandValue<T>>()?.value
-
-/**
- * Value of the integrand or error
- */
-public val <T : Any> UnivariateIntegrand<T>.value: T get() = valueOrNull ?: error("No value in the integrand")
-
 /**
  * A shortcut method to integrate a [function] with additional [features]. Range must be provided in features.
  * The [function] is placed in the end position to allow passing a lambda.
  */
 @UnstableKMathAPI
-public fun <T : Any> UnivariateIntegrator<T>.integrate(
-    vararg features: IntegrandFeature,
-    function: (Double) -> T,
-): UnivariateIntegrand<T> = process(UnivariateIntegrand(function, *features))
-
-/**
- * A shortcut method to integrate a [function] in [range] with additional [features].
- * The [function] is placed in the end position to allow passing a lambda.
- */
-@UnstableKMathAPI
-public fun <T : Any> UnivariateIntegrator<T>.integrate(
-    range: ClosedRange<Double>,
-    vararg features: IntegrandFeature,
-    function: (Double) -> T,
-): UnivariateIntegrand<T> = process(UnivariateIntegrand(function, IntegrationRange(range), *features))
+public inline fun <reified T : Any> UnivariateIntegrator<T>.integrate(
+    noinline attributesBuilder: AttributesBuilder<UnivariateIntegrand<T>>.() -> Unit,
+    noinline function: (Double) -> T,
+): UnivariateIntegrand<T> = integrate(UnivariateIntegrand(attributesBuilder, function))
 
 /**
  * A shortcut method to integrate a [function] in [range] with additional features.
  * The [function] is placed in the end position to allow passing a lambda.
  */
 @UnstableKMathAPI
-public fun <T : Any> UnivariateIntegrator<T>.integrate(
+public inline fun <reified T : Any> UnivariateIntegrator<T>.integrate(
     range: ClosedRange<Double>,
-    featureBuilder: MutableList<IntegrandFeature>.() -> Unit = {},
-    function: (Double) -> T,
+    noinline attributeBuilder: AttributesBuilder<UnivariateIntegrand<T>>.() -> Unit = {},
+    noinline function: (Double) -> T,
 ): UnivariateIntegrand<T> {
-    //TODO use dedicated feature builder class instead or add extensions to MutableList<IntegrandFeature>
-    val features = buildList {
-        featureBuilder()
-        add(IntegrationRange(range))
-    }
-    return process(UnivariateIntegrand(function, *features.toTypedArray()))
+
+    return integrate(
+        UnivariateIntegrand(
+            attributeBuilder = {
+                IntegrationRange(range)
+                attributeBuilder()
+            },
+            function = function
+        )
+    )
 }
diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt
index 191e7dfd9..3b9808028 100644
--- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt
+++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,6 +7,8 @@
 
 package space.kscience.kmath.interpolation
 
+import space.kscience.attributes.SafeType
+import space.kscience.attributes.WithType
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.data.XYColumnarData
 import space.kscience.kmath.functions.PiecewisePolynomial
@@ -26,9 +28,11 @@ public fun interface Interpolator<T, in X : T, Y : T> {
 /**
  * And interpolator returning [PiecewisePolynomial] function
  */
-public interface PolynomialInterpolator<T : Comparable<T>> : Interpolator<T, T, T> {
+public interface PolynomialInterpolator<T : Comparable<T>> : Interpolator<T, T, T>, WithType<T> {
     public val algebra: Ring<T>
 
+    override val type: SafeType<T> get() = algebra.type
+
     public fun getDefaultValue(): T = error("Out of bounds")
 
     public fun interpolatePolynomials(points: XYColumnarData<T, T, T>): PiecewisePolynomial<T>
diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt
index 5c56e406a..e894799c9 100644
--- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt
+++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt
index a3cc17954..2b58f0b05 100644
--- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt
+++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -9,10 +9,9 @@ import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.data.XYColumnarData
 import space.kscience.kmath.functions.PiecewisePolynomial
 import space.kscience.kmath.functions.Polynomial
-import space.kscience.kmath.operations.DoubleField
 import space.kscience.kmath.operations.Field
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.invoke
-import space.kscience.kmath.structures.DoubleBuffer
 import space.kscience.kmath.structures.MutableBufferFactory
 
 /**
@@ -24,7 +23,7 @@ import space.kscience.kmath.structures.MutableBufferFactory
  */
 public class SplineInterpolator<T : Comparable<T>>(
     override val algebra: Field<T>,
-    public val bufferFactory: MutableBufferFactory<T>,
+    public val bufferFactory: MutableBufferFactory<T> = algebra.bufferFactory,
 ) : PolynomialInterpolator<T> {
     //TODO possibly optimize zeroed buffers
 
@@ -79,5 +78,5 @@ public fun <T : Comparable<T>> Field<T>.splineInterpolator(
     bufferFactory: MutableBufferFactory<T>,
 ): SplineInterpolator<T> = SplineInterpolator(this, bufferFactory)
 
-public val DoubleField.splineInterpolator: SplineInterpolator<Double>
-    get() = SplineInterpolator(this, ::DoubleBuffer)
\ No newline at end of file
+public val Float64Field.splineInterpolator: SplineInterpolator<Double>
+    get() = SplineInterpolator(this, bufferFactory)
\ No newline at end of file
diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt
index 3051cdd8d..80f50fcc0 100644
--- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt
+++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,7 +8,8 @@
 package space.kscience.kmath.functions
 
 import space.kscience.kmath.functions.testUtils.*
-import kotlin.test.*
+import kotlin.test.Test
+import kotlin.test.assertEquals
 
 
 class PolynomialTest {
@@ -52,6 +53,7 @@ class PolynomialTest {
             )
         }
     }
+
     @Test
     fun test_Polynomial_Constant_minus() {
         RationalField.polynomialSpace {
@@ -92,6 +94,7 @@ class PolynomialTest {
             )
         }
     }
+
     @Test
     fun test_Polynomial_Constant_times() {
         IntModuloRing(35).polynomialSpace {
@@ -107,6 +110,7 @@ class PolynomialTest {
             )
         }
     }
+
     @Test
     fun test_Constant_Polynomial_plus() {
         RationalField.polynomialSpace {
@@ -147,6 +151,7 @@ class PolynomialTest {
             )
         }
     }
+
     @Test
     fun test_Constant_Polynomial_minus() {
         RationalField.polynomialSpace {
@@ -187,6 +192,7 @@ class PolynomialTest {
             )
         }
     }
+
     @Test
     fun test_Constant_Polynomial_times() {
         IntModuloRing(35).polynomialSpace {
@@ -202,6 +208,7 @@ class PolynomialTest {
             )
         }
     }
+
     @Test
     fun test_Polynomial_unaryMinus() {
         RationalField.polynomialSpace {
@@ -217,6 +224,7 @@ class PolynomialTest {
             )
         }
     }
+
     @Test
     fun test_Polynomial_Polynomial_plus() {
         RationalField.polynomialSpace {
@@ -250,6 +258,7 @@ class PolynomialTest {
             )
         }
     }
+
     @Test
     fun test_Polynomial_Polynomial_minus() {
         RationalField.polynomialSpace {
@@ -283,6 +292,7 @@ class PolynomialTest {
             )
         }
     }
+
     @Test
     fun test_Polynomial_Polynomial_times() {
         IntModuloRing(35).polynomialSpace {
diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt
index 48e641335..b38afdd9e 100644
--- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt
+++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -53,6 +53,7 @@ class PolynomialUtilTest {
             "test 5"
         )
     }
+
     @Test
     fun test_Polynomial_value_Constant() {
         assertEquals(
@@ -85,6 +86,7 @@ class PolynomialUtilTest {
             "test 5"
         )
     }
+
     @Test
     fun test_Polynomial_differentiate() {
         assertEquals(
@@ -94,20 +96,27 @@ class PolynomialUtilTest {
         )
         assertEquals(
             Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)),
-            Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).differentiate(RationalField),
+            Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).differentiate(
+                RationalField
+            ),
             "test 2"
         )
         assertEquals(
             Polynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)),
-            Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).differentiate(RationalField),
+            Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).differentiate(
+                RationalField
+            ),
             "test 3"
         )
         assertEquals(
             Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(0)),
-            Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).differentiate(RationalField),
+            Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).differentiate(
+                RationalField
+            ),
             "test 4"
         )
     }
+
     @Test
     fun test_Polynomial_integrate() {
         assertEquals(
@@ -117,17 +126,23 @@ class PolynomialUtilTest {
         )
         assertEquals(
             Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)),
-            Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).integrate(RationalField),
+            Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).integrate(
+                RationalField
+            ),
             "test 2"
         )
         assertEquals(
             Polynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)),
-            Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).integrate(RationalField),
+            Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).integrate(
+                RationalField
+            ),
             "test 3"
         )
         assertEquals(
             Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(0)),
-            Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).integrate(RationalField),
+            Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).integrate(
+                RationalField
+            ),
             "test 4"
         )
     }
diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt
index 3b7409e82..ceb80d7dd 100644
--- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt
+++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -9,6 +9,7 @@ package space.kscience.kmath.functions.testUtils
 
 import space.kscience.kmath.operations.Ring
 import space.kscience.kmath.operations.ScaleOperations
+import space.kscience.kmath.structures.MutableBufferFactory
 
 
 class IntModulo {
@@ -36,6 +37,7 @@ class IntModulo {
             modulus,
             toCheckInput = false
         )
+
     operator fun plus(other: IntModulo): IntModulo {
         require(modulus == other.modulus) { "can not add two residue different modulo" }
         return IntModulo(
@@ -44,12 +46,14 @@ class IntModulo {
             toCheckInput = false
         )
     }
+
     operator fun plus(other: Int): IntModulo =
         IntModulo(
             (residue + other) % modulus,
             modulus,
             toCheckInput = false
         )
+
     operator fun minus(other: IntModulo): IntModulo {
         require(modulus == other.modulus) { "can not subtract two residue different modulo" }
         return IntModulo(
@@ -58,12 +62,14 @@ class IntModulo {
             toCheckInput = false
         )
     }
+
     operator fun minus(other: Int): IntModulo =
         IntModulo(
             (residue - other) % modulus,
             modulus,
             toCheckInput = false
         )
+
     operator fun times(other: IntModulo): IntModulo {
         require(modulus == other.modulus) { "can not multiply two residue different modulo" }
         return IntModulo(
@@ -72,12 +78,14 @@ class IntModulo {
             toCheckInput = false
         )
     }
+
     operator fun times(other: Int): IntModulo =
         IntModulo(
             (residue * other) % modulus,
             modulus,
             toCheckInput = false
         )
+
     operator fun div(other: IntModulo): IntModulo {
         require(modulus == other.modulus) { "can not divide two residue different modulo" }
         val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus)
@@ -88,6 +96,7 @@ class IntModulo {
             toCheckInput = false
         )
     }
+
     operator fun div(other: Int): IntModulo {
         val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus)
         require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" }
@@ -97,6 +106,7 @@ class IntModulo {
             toCheckInput = false
         )
     }
+
     override fun equals(other: Any?): Boolean =
         when (other) {
             is IntModulo -> residue == other.residue && modulus == other.modulus
@@ -109,15 +119,17 @@ class IntModulo {
 }
 
 @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE")
-class IntModuloRing : Ring<IntModulo>, ScaleOperations<IntModulo> {
+class IntModuloRing(modulus: Int) : Ring<IntModulo>, ScaleOperations<IntModulo> {
 
     val modulus: Int
 
-    constructor(modulus: Int) {
+    init {
         require(modulus != 0) { "modulus can not be zero" }
         this.modulus = if (modulus < 0) -modulus else modulus
     }
 
+    override val bufferFactory: MutableBufferFactory<IntModulo> = MutableBufferFactory()
+
     override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false)
     override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false)
 
diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt
index ffab2157c..c6a8e16cd 100644
--- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt
+++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -11,6 +11,7 @@ import space.kscience.kmath.functions.PolynomialSpace
 
 fun PolynomialSpace<IntModulo, IntModuloRing>.Polynomial(vararg coefs: Int): Polynomial<IntModulo> =
     Polynomial(coefs.map { IntModulo(it, ring.modulus) })
+
 fun IntModuloRing.Polynomial(vararg coefs: Int): Polynomial<IntModulo> =
     Polynomial(coefs.map { IntModulo(it, modulus) })
 
diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt
index ff05805da..0160b2c97 100644
--- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt
+++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -10,6 +10,7 @@ package space.kscience.kmath.functions.testUtils
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.operations.Field
 import space.kscience.kmath.operations.NumbersAddOps
+import space.kscience.kmath.structures.MutableBufferFactory
 
 @Suppress("NAME_SHADOWING")
 class Rational {
@@ -56,18 +57,21 @@ class Rational {
             toCheckInput = false
         )
     }
+
     operator fun plus(other: Int): Rational =
         Rational(
             numerator + denominator * other.toLong(),
             denominator,
             toCheckInput = false
         )
+
     operator fun plus(other: Long): Rational =
         Rational(
             numerator + denominator * other,
             denominator,
             toCheckInput = false
         )
+
     operator fun minus(other: Rational): Rational {
         val denominatorsGcd = gcd(denominator, other.denominator)
         val dividedThisDenominator = denominator / denominatorsGcd
@@ -80,18 +84,21 @@ class Rational {
             toCheckInput = false
         )
     }
+
     operator fun minus(other: Int): Rational =
         Rational(
             numerator - denominator * other.toLong(),
             denominator,
             toCheckInput = false
         )
+
     operator fun minus(other: Long): Rational =
         Rational(
             numerator - denominator * other,
             denominator,
             toCheckInput = false
         )
+
     operator fun times(other: Rational): Rational {
         val thisDenominatorAndOtherNumeratorGcd = gcd(denominator, other.numerator)
         val otherDenominatorAndThisNumeratorGcd = gcd(other.denominator, numerator)
@@ -101,6 +108,7 @@ class Rational {
             toCheckInput = false
         )
     }
+
     operator fun times(other: Int): Rational {
         val other = other.toLong()
         val denominatorAndOtherGcd = gcd(denominator, other)
@@ -110,6 +118,7 @@ class Rational {
             toCheckInput = false
         )
     }
+
     operator fun times(other: Long): Rational {
         val denominatorAndOtherGcd = gcd(denominator, other)
         return Rational(
@@ -118,6 +127,7 @@ class Rational {
             toCheckInput = false
         )
     }
+
     operator fun div(other: Rational): Rational {
         val denominatorsGcd = gcd(denominator, other.denominator)
         val numeratorsGcd = gcd(numerator, other.numerator)
@@ -126,6 +136,7 @@ class Rational {
             (denominator / denominatorsGcd) * (other.numerator / numeratorsGcd)
         )
     }
+
     operator fun div(other: Int): Rational {
         val other = other.toLong()
         val numeratorAndOtherGcd = gcd(numerator, other)
@@ -135,6 +146,7 @@ class Rational {
             toCheckInput = false
         )
     }
+
     operator fun div(other: Long): Rational {
         val numeratorAndOtherGcd = gcd(numerator, other)
         return Rational(
@@ -143,6 +155,7 @@ class Rational {
             toCheckInput = false
         )
     }
+
     override fun equals(other: Any?): Boolean =
         when (other) {
             is Rational -> numerator == other.numerator && denominator == other.denominator
@@ -159,6 +172,7 @@ class Rational {
 @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE")
 @OptIn(UnstableKMathAPI::class)
 object RationalField : Field<Rational>, NumbersAddOps<Rational> {
+    override val bufferFactory: MutableBufferFactory<Rational> = MutableBufferFactory()
     override inline val zero: Rational get() = Rational.ZERO
     override inline val one: Rational get() = Rational.ONE
 
diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt
index 61b50f128..6f728a53d 100644
--- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt
+++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -14,13 +14,41 @@ internal tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(
 
 internal fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD<Int> =
     when {
-        a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) }
-        a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) }
-        b < 0 -> with(bezoutIdentityWithGCDInternalLogic(a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(first, -second, gcd) }
+        a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) {
+            BezoutIdentityWithGCD(
+                -first,
+                -second,
+                gcd
+            )
+        }
+
+        a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) {
+            BezoutIdentityWithGCD(
+                -first,
+                second,
+                gcd
+            )
+        }
+
+        b < 0 -> with(bezoutIdentityWithGCDInternalLogic(a, -b, 1, 0, 0, 1)) {
+            BezoutIdentityWithGCD(
+                first,
+                -second,
+                gcd
+            )
+        }
+
         else -> bezoutIdentityWithGCDInternalLogic(a, b, 1, 0, 0, 1)
     }
 
-internal tailrec fun bezoutIdentityWithGCDInternalLogic(a: Int, b: Int, m1: Int, m2: Int, m3: Int, m4: Int): BezoutIdentityWithGCD<Int> =
+internal tailrec fun bezoutIdentityWithGCDInternalLogic(
+    a: Int,
+    b: Int,
+    m1: Int,
+    m2: Int,
+    m3: Int,
+    m4: Int,
+): BezoutIdentityWithGCD<Int> =
     if (b == 0) BezoutIdentityWithGCD(m1, m3, a)
     else {
         val quotient = a / b
diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt
index 7424f3566..db6bdc6bd 100644
--- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt
+++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt
@@ -1,12 +1,12 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.integration
 
 import space.kscience.kmath.UnstableKMathAPI
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import kotlin.math.PI
 import kotlin.math.sin
 import kotlin.test.Test
@@ -16,7 +16,7 @@ import kotlin.test.assertEquals
 class GaussIntegralTest {
     @Test
     fun gaussSin() {
-        val res = DoubleField.gaussIntegrator.integrate(0.0..2 * PI) { x ->
+        val res = Float64Field.gaussIntegrator.integrate(0.0..2 * PI) { x ->
             sin(x)
         }
         assertEquals(0.0, res.value, 1e-2)
@@ -24,8 +24,8 @@ class GaussIntegralTest {
 
     @Test
     fun gaussUniform() {
-        val res = DoubleField.gaussIntegrator.integrate(35.0..100.0) { x ->
-            if(x in 30.0..50.0){
+        val res = Float64Field.gaussIntegrator.integrate(35.0..100.0) { x ->
+            if (x in 30.0..50.0) {
                 1.0
             } else {
                 0.0
diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt
index 7b699ebbc..a4af7dc82 100644
--- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt
+++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt
@@ -1,12 +1,12 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.integration
 
 import space.kscience.kmath.UnstableKMathAPI
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import kotlin.math.PI
 import kotlin.math.sin
 import kotlin.test.Test
@@ -16,7 +16,10 @@ import kotlin.test.assertEquals
 class SimpsonIntegralTest {
     @Test
     fun gaussSin() {
-        val res = DoubleField.simpsonIntegrator.integrate(0.0..2 * PI, IntegrandMaxCalls(5)) { x ->
+        val res = Float64Field.simpsonIntegrator.integrate(
+            0.0..2 * PI,
+            { IntegrandMaxCalls(5) }
+        ) { x ->
             sin(x)
         }
         assertEquals(0.0, res.value, 1e-2)
@@ -24,7 +27,10 @@ class SimpsonIntegralTest {
 
     @Test
     fun gaussUniform() {
-        val res = DoubleField.simpsonIntegrator.integrate(35.0..100.0, IntegrandMaxCalls(20)) { x ->
+        val res = Float64Field.simpsonIntegrator.integrate(
+            35.0..100.0,
+            { IntegrandMaxCalls(20) }
+        ) { x ->
             if (x in 30.0..50.0) {
                 1.0
             } else {
diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt
index b17d21abf..946f8811c 100644
--- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt
+++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,7 +8,7 @@ package space.kscience.kmath.integration
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.functions.Polynomial
 import space.kscience.kmath.functions.integrate
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import kotlin.math.PI
 import kotlin.math.sin
 import kotlin.test.Test
@@ -18,15 +18,15 @@ import kotlin.test.assertEquals
 class SplineIntegralTest {
 
     @Test
-    fun integratePolynomial(){
+    fun integratePolynomial() {
         val polynomial = Polynomial(1.0, 2.0, 3.0)
-        val integral = polynomial.integrate(DoubleField,1.0..2.0)
+        val integral = polynomial.integrate(Float64Field, 1.0..2.0)
         assertEquals(11.0, integral, 0.001)
     }
 
     @Test
     fun gaussSin() {
-        val res = DoubleField.splineIntegrator.integrate(0.0..2 * PI, IntegrandMaxCalls(5)) { x ->
+        val res = Float64Field.splineIntegrator.integrate(0.0..2 * PI, { IntegrandMaxCalls(5) }) { x ->
             sin(x)
         }
         assertEquals(0.0, res.value, 1e-2)
@@ -34,8 +34,8 @@ class SplineIntegralTest {
 
     @Test
     fun gaussUniform() {
-        val res = DoubleField.splineIntegrator.integrate(35.0..100.0, IntegrandMaxCalls(20)) { x ->
-            if(x in 30.0..50.0){
+        val res = Float64Field.splineIntegrator.integrate(35.0..100.0, { IntegrandMaxCalls(20) }) { x ->
+            if (x in 30.0..50.0) {
                 1.0
             } else {
                 0.0
diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt
index c0ca6c484..c62d2c8bc 100644
--- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt
+++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt
@@ -1,11 +1,11 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.interpolation
 
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import kotlin.test.Test
 import kotlin.test.assertEquals
 
@@ -20,7 +20,7 @@ internal class LinearInterpolatorTest {
         )
 
         //val polynomial: PiecewisePolynomial<Double> = DoubleField.linearInterpolator.interpolatePolynomials(data)
-        val function = DoubleField.linearInterpolator.interpolate(data)
+        val function = Float64Field.linearInterpolator.interpolate(data)
         assertEquals(null, function(-1.0))
         assertEquals(0.5, function(0.5))
         assertEquals(2.0, function(1.5))
diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt
index 851a8ab7d..8869a1f45 100644
--- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt
+++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt
@@ -1,11 +1,11 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.interpolation
 
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import kotlin.math.PI
 import kotlin.math.sin
 import kotlin.test.Test
@@ -21,7 +21,7 @@ internal class SplineInterpolatorTest {
 
         //val polynomial: PiecewisePolynomial<Double> = DoubleField.splineInterpolator.interpolatePolynomials(data)
 
-        val function = DoubleField.splineInterpolator.interpolate(data, Double.NaN)
+        val function = Float64Field.splineInterpolator.interpolate(data, Double.NaN)
 
         assertEquals(Double.NaN, function(-1.0))
         assertEquals(sin(0.5), function(0.5), 0.1)
diff --git a/kmath-geometry/README.md b/kmath-geometry/README.md
index 480945c4f..eed6b6cfd 100644
--- a/kmath-geometry/README.md
+++ b/kmath-geometry/README.md
@@ -6,19 +6,8 @@
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-geometry:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-geometry:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-geometry:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -27,6 +16,6 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-geometry:0.4.0-dev-1")
+    implementation("space.kscience:kmath-geometry:0.4.0")
 }
 ```
diff --git a/kmath-geometry/build.gradle.kts b/kmath-geometry/build.gradle.kts
index 32926db7e..58bbbf5d0 100644
--- a/kmath-geometry/build.gradle.kts
+++ b/kmath-geometry/build.gradle.kts
@@ -2,14 +2,15 @@ plugins {
     id("space.kscience.gradle.mpp")
 }
 
-kscience{
+kscience {
     jvm()
     js()
     native()
+    wasm()
 
     useContextReceivers()
     useSerialization()
-    dependencies{
+    dependencies {
         api(projects.kmath.kmathComplex)
     }
 
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt
deleted file mode 100644
index d37ed45c0..000000000
--- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 2018-2022 KMath contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package space.kscience.kmath.geometry
-
-import kotlinx.serialization.Serializable
-import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo
-import kotlin.math.*
-
-/**
- * A circle in 2D space
- */
-@Serializable
-public data class Circle2D(
-    @Serializable(Euclidean2DSpace.VectorSerializer::class) public val center: DoubleVector2D,
-    public val radius: Double
-)
-
-
-public val Circle2D.circumference: Double get() = radius * 2 * PI
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt
deleted file mode 100644
index 3df8dba7b..000000000
--- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2018-2022 KMath contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package space.kscience.kmath.geometry
-
-import kotlinx.serialization.KSerializer
-import kotlinx.serialization.SerialName
-import kotlinx.serialization.Serializable
-import kotlinx.serialization.descriptors.SerialDescriptor
-import kotlinx.serialization.encoding.Decoder
-import kotlinx.serialization.encoding.Encoder
-import space.kscience.kmath.linear.Point
-import space.kscience.kmath.operations.Norm
-import space.kscience.kmath.operations.ScaleOperations
-import kotlin.math.pow
-import kotlin.math.sqrt
-
-public interface Vector2D<T> : Point<T>, Vector {
-    public val x: T
-    public val y: T
-    override val size: Int get() = 2
-
-    override operator fun get(index: Int): T = when (index) {
-        0 -> x
-        1 -> y
-        else -> error("Accessing outside of point bounds")
-    }
-
-    override operator fun iterator(): Iterator<T> = iterator {
-        yield(x)
-        yield(y)
-    }
-}
-
-
-public operator fun <T> Vector2D<T>.component1(): T = x
-public operator fun <T> Vector2D<T>.component2(): T = y
-
-public typealias DoubleVector2D = Vector2D<Double>
-public typealias Float64Vector2D = Vector2D<Double>
-
-public val Vector2D<Double>.r: Double get() = Euclidean2DSpace.norm(this)
-
-
-/**
- * 2D Euclidean space
- */
-public object Euclidean2DSpace : GeometrySpace<DoubleVector2D>,
-    ScaleOperations<DoubleVector2D>,
-    Norm<DoubleVector2D, Double> {
-
-    @Serializable
-    @SerialName("Float64Vector2D")
-    private data class Vector2DImpl(
-        override val x: Double,
-        override val y: Double,
-    ) : DoubleVector2D
-
-    public object VectorSerializer : KSerializer<DoubleVector2D> {
-        private val proxySerializer = Vector2DImpl.serializer()
-        override val descriptor: SerialDescriptor get() = proxySerializer.descriptor
-
-        override fun deserialize(decoder: Decoder): DoubleVector2D = decoder.decodeSerializableValue(proxySerializer)
-
-        override fun serialize(encoder: Encoder, value: DoubleVector2D) {
-            val vector = value as? Vector2DImpl ?: Vector2DImpl(value.x, value.y)
-            encoder.encodeSerializableValue(proxySerializer, vector)
-        }
-    }
-
-    public fun vector(x: Number, y: Number): DoubleVector2D = Vector2DImpl(x.toDouble(), y.toDouble())
-
-    override val zero: DoubleVector2D by lazy { vector(0.0, 0.0) }
-
-    override fun norm(arg: DoubleVector2D): Double = sqrt(arg.x.pow(2) + arg.y.pow(2))
-
-    override fun DoubleVector2D.unaryMinus(): DoubleVector2D = vector(-x, -y)
-
-    override fun DoubleVector2D.distanceTo(other: DoubleVector2D): Double = norm(this - other)
-    override fun add(left: DoubleVector2D, right: DoubleVector2D): DoubleVector2D =
-        vector(left.x + right.x, left.y + right.y)
-
-    override fun scale(a: DoubleVector2D, value: Double): DoubleVector2D = vector(a.x * value, a.y * value)
-    override fun DoubleVector2D.dot(other: DoubleVector2D): Double = x * other.x + y * other.y
-
-    public val xAxis: DoubleVector2D = vector(1.0, 0.0)
-    public val yAxis: DoubleVector2D = vector(0.0, 1.0)
-}
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt
deleted file mode 100644
index 3059cefe6..000000000
--- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright 2018-2022 KMath contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package space.kscience.kmath.geometry
-
-import kotlinx.serialization.KSerializer
-import kotlinx.serialization.SerialName
-import kotlinx.serialization.Serializable
-import kotlinx.serialization.descriptors.SerialDescriptor
-import kotlinx.serialization.encoding.Decoder
-import kotlinx.serialization.encoding.Encoder
-import space.kscience.kmath.linear.Point
-import space.kscience.kmath.operations.Norm
-import space.kscience.kmath.operations.ScaleOperations
-import space.kscience.kmath.structures.Buffer
-import kotlin.math.pow
-import kotlin.math.sqrt
-
-public interface Vector3D<T> : Point<T>, Vector {
-    public val x: T
-    public val y: T
-    public val z: T
-    override val size: Int get() = 3
-
-    override operator fun get(index: Int): T = when (index) {
-        0 -> x
-        1 -> y
-        2 -> z
-        else -> error("Accessing outside of point bounds")
-    }
-
-    override operator fun iterator(): Iterator<T> = listOf(x, y, z).iterator()
-}
-
-public operator fun <T> Vector3D<T>.component1(): T = x
-public operator fun <T> Vector3D<T>.component2(): T = y
-public operator fun <T> Vector3D<T>.component3(): T = z
-
-public fun <T> Buffer<T>.asVector3D(): Vector3D<T> = object : Vector3D<T> {
-    init {
-        require(this@asVector3D.size == 3) { "Buffer of size 3 is required for Vector3D" }
-    }
-
-    override val x: T get() = this@asVector3D[0]
-    override val y: T get() = this@asVector3D[1]
-    override val z: T get() = this@asVector3D[2]
-
-    override fun toString(): String = this@asVector3D.toString()
-}
-
-public typealias DoubleVector3D = Vector3D<Double>
-public typealias Float64Vector3D = Vector3D<Double>
-
-public val DoubleVector3D.r: Double get() = Euclidean3DSpace.norm(this)
-
-public object Euclidean3DSpace : GeometrySpace<DoubleVector3D>, ScaleOperations<DoubleVector3D>,
-    Norm<DoubleVector3D, Double> {
-
-    @Serializable
-    @SerialName("Float64Vector3D")
-    private data class Vector3DImpl(
-        override val x: Double,
-        override val y: Double,
-        override val z: Double,
-    ) : DoubleVector3D
-
-    public object VectorSerializer : KSerializer<DoubleVector3D> {
-        private val proxySerializer = Vector3DImpl.serializer()
-        override val descriptor: SerialDescriptor get() = proxySerializer.descriptor
-
-        override fun deserialize(decoder: Decoder): DoubleVector3D = decoder.decodeSerializableValue(proxySerializer)
-
-        override fun serialize(encoder: Encoder, value: DoubleVector3D) {
-            val vector = value as? Vector3DImpl ?: Vector3DImpl(value.x, value.y, value.z)
-            encoder.encodeSerializableValue(proxySerializer, vector)
-        }
-    }
-
-    public fun vector(x: Double, y: Double, z: Double): DoubleVector3D =
-        Vector3DImpl(x, y, z)
-
-    public fun vector(x: Number, y: Number, z: Number): DoubleVector3D =
-        vector(x.toDouble(), y.toDouble(), z.toDouble())
-
-    override val zero: DoubleVector3D by lazy { vector(0.0, 0.0, 0.0) }
-
-    override fun norm(arg: DoubleVector3D): Double = sqrt(arg.x.pow(2) + arg.y.pow(2) + arg.z.pow(2))
-
-    public fun DoubleVector3D.norm(): Double = norm(this)
-
-    override fun DoubleVector3D.unaryMinus(): DoubleVector3D = vector(-x, -y, -z)
-
-    override fun DoubleVector3D.distanceTo(other: DoubleVector3D): Double = (this - other).norm()
-
-    override fun add(left: DoubleVector3D, right: DoubleVector3D): DoubleVector3D =
-        vector(left.x + right.x, left.y + right.y, left.z + right.z)
-
-    override fun scale(a: DoubleVector3D, value: Double): DoubleVector3D =
-        vector(a.x * value, a.y * value, a.z * value)
-
-    override fun DoubleVector3D.dot(other: DoubleVector3D): Double =
-        x * other.x + y * other.y + z * other.z
-
-    private fun leviCivita(i: Int, j: Int, k: Int): Int = when {
-        // even permutation
-        i == 0 && j == 1 && k == 2 -> 1
-        i == 1 && j == 2 && k == 0 -> 1
-        i == 2 && j == 0 && k == 1 -> 1
-        // odd permutations
-        i == 2 && j == 1 && k == 0 -> -1
-        i == 0 && j == 2 && k == 1 -> -1
-        i == 1 && j == 0 && k == 2 -> -1
-
-        else -> 0
-    }
-
-    /**
-     * Compute vector product of [first] and [second]. The basis assumed to be right-handed.
-     */
-    public fun vectorProduct(
-        first: DoubleVector3D,
-        second: DoubleVector3D,
-    ): DoubleVector3D {
-        var x = 0.0
-        var y = 0.0
-        var z = 0.0
-
-        for (j in (0..2)) {
-            for (k in (0..2)) {
-                x += leviCivita(0, j, k) * first[j] * second[k]
-                y += leviCivita(1, j, k) * first[j] * second[k]
-                z += leviCivita(2, j, k) * first[j] * second[k]
-            }
-        }
-
-        return vector(x, y, z)
-    }
-
-    /**
-     * Vector product with right basis
-     */
-    public infix fun DoubleVector3D.cross(other: DoubleVector3D): Vector3D<Double> = vectorProduct(this, other)
-
-    public val xAxis: DoubleVector3D = vector(1.0, 0.0, 0.0)
-    public val yAxis: DoubleVector3D = vector(0.0, 1.0, 0.0)
-    public val zAxis: DoubleVector3D = vector(0.0, 0.0, 1.0)
-}
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt
index d6d7e5725..d11378795 100644
--- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt
+++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -9,23 +9,26 @@ import space.kscience.kmath.operations.Group
 import space.kscience.kmath.operations.Norm
 import space.kscience.kmath.operations.ScaleOperations
 
-public interface Vector
-
-public interface GeometrySpace<V : Vector> : Group<V>, ScaleOperations<V>, Norm<V, Double> {
+/**
+ * A geometry vector space
+ * @param V the type of vector object
+ * @param D the type of distance
+ */
+public interface GeometrySpace<V : Any, D : Comparable<D>> : Group<V>, ScaleOperations<V>, Norm<V, D> {
     /**
      * L2 distance
      */
-    public fun V.distanceTo(other: V): Double
+    public fun V.distanceTo(other: V): D
 
     /**
      * Scalar product
      */
     public infix fun V.dot(other: V): Double
 
-    public companion object{
-        /**
-         * Default precision for geometry objects comparison
-         */
-        internal const val DEFAULT_PRECISION = 1e-6
-    }
+    /**
+     * Default precision for geometry objects comparison
+     */
+    public val defaultPrecision: D
+
+    public companion object
 }
\ No newline at end of file
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt
index a7f6ae35d..c65ccd43d 100644
--- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt
+++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,29 +7,30 @@ package space.kscience.kmath.geometry
 
 import kotlinx.serialization.SerialName
 import kotlinx.serialization.Serializable
+import space.kscience.kmath.structures.Float64
 
 /**
  * A line formed by [start] vector of start and a [direction] vector. Direction vector is not necessarily normalized,
  * but its length does not affect line properties
  */
-public interface Line<out V : Vector> {
+public interface Line<out V : Any> {
     public val start: V
     public val direction: V
 }
 
 @Serializable
 @SerialName("Line")
-private data class LineImpl<out V : Vector>(override val start: V, override val direction: V): Line<V>
+private data class LineImpl<out V : Any>(override val start: V, override val direction: V) : Line<V>
 
-public fun <V : Vector> Line(base: V, direction: V): Line<V> = LineImpl(base, direction)
+public fun <V : Any> Line(base: V, direction: V): Line<V> = LineImpl(base, direction)
 
-public typealias Line2D = Line<DoubleVector2D>
-public typealias Line3D = Line<DoubleVector3D>
+public typealias Line2D = Line<Vector2D<Float64>>
+public typealias Line3D = Line<Vector3D<Float64>>
 
 /**
  * A directed line segment between [begin] and [end]
  */
-public interface LineSegment<out V : Vector> {
+public interface LineSegment<out V : Any> {
     public val begin: V
     public val end: V
 }
@@ -39,13 +40,13 @@ public interface LineSegment<out V : Vector> {
  */
 @Serializable
 @SerialName("LineSegment")
-private data class LineSegmentImpl<out V : Vector>(override val begin: V, override val end: V) : LineSegment<V>
+private data class LineSegmentImpl<out V : Any>(override val begin: V, override val end: V) : LineSegment<V>
 
-public fun <V : Vector> LineSegment(begin: V, end: V): LineSegment<V> = LineSegmentImpl(begin, end)
+public fun <V : Any> LineSegment(begin: V, end: V): LineSegment<V> = LineSegmentImpl(begin, end)
 
-public fun <V : Vector> LineSegment<V>.line(algebra: GeometrySpace<V>): Line<V> = with(algebra) {
+public fun <V : Any> LineSegment<V>.line(algebra: GeometrySpace<V, *>): Line<V> = with(algebra) {
     Line(begin, end - begin)
 }
 
-public typealias LineSegment2D = LineSegment<DoubleVector2D>
-public typealias LineSegment3D = LineSegment<DoubleVector3D>
+public typealias LineSegment2D = LineSegment<Vector2D<Float64>>
+public typealias LineSegment3D = LineSegment<Vector3D<Float64>>
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Polygon.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Polygon.kt
index 20f4a031e..1d832cb8a 100644
--- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Polygon.kt
+++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Polygon.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2023 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -9,6 +9,6 @@ package space.kscience.kmath.geometry
 /**
  * A closed polygon in 2D space
  */
-public interface Polygon<T> {
-    public val points: List<Vector2D<T>>
+public interface Polygon<V : Any> {
+    public val points: List<V>
 }
\ No newline at end of file
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/ReferenceFrame.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/ReferenceFrame.kt
index 21045e94e..f28bc6539 100644
--- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/ReferenceFrame.kt
+++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/ReferenceFrame.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Vector2D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Vector2D.kt
new file mode 100644
index 000000000..f01b4c576
--- /dev/null
+++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Vector2D.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.geometry
+
+import space.kscience.kmath.linear.Point
+
+public interface Vector2D<T> : Point<T> {
+    public val x: T
+    public val y: T
+    override val size: Int get() = 2
+
+    override operator fun get(index: Int): T = when (index) {
+        0 -> x
+        1 -> y
+        else -> error("Accessing outside of point bounds")
+    }
+
+    override operator fun iterator(): Iterator<T> = iterator {
+        yield(x)
+        yield(y)
+    }
+}
+
+
+public operator fun <T> Vector2D<T>.component1(): T = x
+public operator fun <T> Vector2D<T>.component2(): T = y
\ No newline at end of file
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Vector3D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Vector3D.kt
new file mode 100644
index 000000000..71442cf63
--- /dev/null
+++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Vector3D.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.geometry
+
+import space.kscience.kmath.linear.Point
+import space.kscience.kmath.structures.Buffer
+
+public interface Vector3D<T> : Point<T> {
+    public val x: T
+    public val y: T
+    public val z: T
+    override val size: Int get() = 3
+
+    override operator fun get(index: Int): T = when (index) {
+        0 -> x
+        1 -> y
+        2 -> z
+        else -> error("Accessing outside of point bounds")
+    }
+
+    override operator fun iterator(): Iterator<T> = listOf(x, y, z).iterator()
+}
+
+public operator fun <T> Vector3D<T>.component1(): T = x
+public operator fun <T> Vector3D<T>.component2(): T = y
+public operator fun <T> Vector3D<T>.component3(): T = z
+
+public fun <T> Buffer<T>.asVector3D(): Vector3D<T> = object : Vector3D<T> {
+    init {
+        require(this@asVector3D.size == 3) { "Buffer of size 3 is required for Vector3D" }
+    }
+
+    override val x: T get() = this@asVector3D[0]
+    override val y: T get() = this@asVector3D[1]
+    override val z: T get() = this@asVector3D[2]
+
+    override fun toString(): String = this@asVector3D.toString()
+}
\ No newline at end of file
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/angles.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/angles.kt
index 3855514fb..8598bdcc9 100644
--- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/angles.kt
+++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/angles.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2021 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -11,6 +11,8 @@ import kotlinx.serialization.builtins.serializer
 import kotlinx.serialization.descriptors.SerialDescriptor
 import kotlinx.serialization.encoding.Decoder
 import kotlinx.serialization.encoding.Encoder
+import space.kscience.kmath.operations.Group
+import space.kscience.kmath.structures.MutableBufferFactory
 import kotlin.jvm.JvmInline
 import kotlin.math.PI
 import kotlin.math.floor
@@ -28,11 +30,19 @@ public sealed interface Angle : Comparable<Angle> {
     public operator fun div(other: Angle): Double
     public operator fun unaryMinus(): Angle
 
-    public companion object {
-        public val zero: Radians = Radians(0.0)
+    public companion object : Group<Angle> {
+        override val zero: Radians = Radians(0.0)
         public val pi: Radians = Radians(PI)
         public val piTimes2: Radians = Radians(PI * 2)
         public val piDiv2: Radians = Radians(PI / 2)
+
+
+        override fun add(left: Angle, right: Angle): Angle = left + right
+
+        @Suppress("EXTENSION_SHADOWED_BY_MEMBER")
+        override fun Angle.unaryMinus(): Angle = -this
+
+        override val bufferFactory: MutableBufferFactory<Angle> = MutableBufferFactory()
     }
 }
 
@@ -43,7 +53,7 @@ public object AngleSerializer : KSerializer<Angle> {
     override fun deserialize(decoder: Decoder): Angle = decoder.decodeDouble().degrees
 
     override fun serialize(encoder: Encoder, value: Angle) {
-        encoder.encodeDouble(value.degrees)
+        encoder.encodeDouble(value.toDegrees().value)
     }
 }
 
@@ -56,16 +66,16 @@ public value class Radians(public val value: Double) : Angle {
     override fun toRadians(): Radians = this
     override fun toDegrees(): Degrees = Degrees(value * 180 / PI)
 
-    public override fun plus(other: Angle): Radians = Radians(value + other.radians)
-    public override fun minus(other: Angle): Radians = Radians(value - other.radians)
+    public override fun plus(other: Angle): Radians = Radians(value + other.toRadians().value)
+    public override fun minus(other: Angle): Radians = Radians(value - other.toRadians().value)
 
     public override fun times(other: Number): Radians = Radians(value * other.toDouble())
     public override fun div(other: Number): Radians = Radians(value / other.toDouble())
-    override fun div(other: Angle): Double = value / other.radians
+    override fun div(other: Angle): Double = value / other.toRadians().value
 
     public override fun unaryMinus(): Radians = Radians(-value)
 
-    override fun compareTo(other: Angle): Int = value.compareTo(other.radians)
+    override fun compareTo(other: Angle): Int = value.compareTo(other.toRadians().value)
 }
 
 public fun sin(angle: Angle): Double = kotlin.math.sin(angle.toRadians().value)
@@ -74,6 +84,7 @@ public fun tan(angle: Angle): Double = kotlin.math.tan(angle.toRadians().value)
 
 public val Number.radians: Radians get() = Radians(toDouble())
 
+@Deprecated("Convert to radians", ReplaceWith("toRadians().value"))
 public val Angle.radians: Double get() = toRadians().value
 
 /**
@@ -84,26 +95,27 @@ public value class Degrees(public val value: Double) : Angle {
     override fun toRadians(): Radians = Radians(value * PI / 180)
     override fun toDegrees(): Degrees = this
 
-    public override fun plus(other: Angle): Degrees = Degrees(value + other.degrees)
-    public override fun minus(other: Angle): Degrees = Degrees(value - other.degrees)
+    public override fun plus(other: Angle): Degrees = Degrees(value + other.toDegrees().value)
+    public override fun minus(other: Angle): Degrees = Degrees(value - other.toDegrees().value)
 
     public override fun times(other: Number): Degrees = Degrees(value * other.toDouble())
     public override fun div(other: Number): Degrees = Degrees(value / other.toDouble())
-    override fun div(other: Angle): Double = value / other.degrees
+    override fun div(other: Angle): Double = value / other.toDegrees().value
 
     public override fun unaryMinus(): Degrees = Degrees(-value)
 
-    override fun compareTo(other: Angle): Int = value.compareTo(other.degrees)
+    override fun compareTo(other: Angle): Int = value.compareTo(other.toDegrees().value)
 }
 
 public val Number.degrees: Degrees get() = Degrees(toDouble())
 
+@Deprecated("Convert to degrees", ReplaceWith("toDegrees().value"))
 public val Angle.degrees: Double get() = toDegrees().value
 
 /**
  * Normalized angle 2 PI range symmetric around [center]. By default, uses (0, 2PI) range.
  */
 public fun Angle.normalized(center: Angle = Angle.pi): Angle =
-    this - Angle.piTimes2 * floor((radians + PI - center.radians) / PI / 2)
+    this - Angle.piTimes2 * floor((toRadians().value + PI - center.toRadians().value) / PI / 2)
 
 public fun abs(angle: Angle): Angle = if (angle < Angle.zero) -angle else angle
\ No newline at end of file
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Circle2D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Circle2D.kt
new file mode 100644
index 000000000..fcffc7714
--- /dev/null
+++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Circle2D.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.geometry.euclidean2d
+
+import kotlinx.serialization.Serializable
+import space.kscience.kmath.geometry.Vector2D
+import space.kscience.kmath.structures.Float64
+import kotlin.math.PI
+
+
+public interface Circle2D<T> {
+    public val center: Vector2D<T>
+    public val radius: Double
+}
+
+public val Circle2D<*>.circumference: Double get() = radius * 2 * PI
+
+/**
+ * A circle in 2D space
+ */
+@Serializable
+public data class Float64Circle2D(
+    @Serializable(Float64Space2D.VectorSerializer::class) override val center: Float64Vector2D,
+    override val radius: Float64,
+) : Circle2D<Double>
+
+public fun Circle2D(center: Vector2D<Float64>, radius: Double): Circle2D<Double> = Float64Circle2D(
+    center as? Float64Vector2D ?: Float64Vector2D(center.x, center.y),
+    radius
+)
+
+
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Float32Space2D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Float32Space2D.kt
new file mode 100644
index 000000000..ae140ff06
--- /dev/null
+++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Float32Space2D.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.geometry.euclidean2d
+
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.descriptors.SerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
+import space.kscience.kmath.geometry.GeometrySpace
+import space.kscience.kmath.geometry.Vector2D
+import space.kscience.kmath.operations.Float32Field
+import space.kscience.kmath.structures.Float32
+import space.kscience.kmath.structures.MutableBufferFactory
+import kotlin.math.pow
+import kotlin.math.sqrt
+
+
+public typealias Float32Vector2D = Vector2D<Float32>
+
+
+public object Float32Space2D : GeometrySpace<Vector2D<Float32>, Float32> {
+    @Serializable
+    @SerialName("Float32Vector2D")
+    private data class Vector2DImpl(
+        override val x: Float,
+        override val y: Float,
+    ) : Float32Vector2D
+
+    public object VectorSerializer : KSerializer<Float32Vector2D> {
+        private val proxySerializer = Vector2DImpl.serializer()
+        override val descriptor: SerialDescriptor get() = proxySerializer.descriptor
+
+        override fun deserialize(decoder: Decoder): Float32Vector2D = decoder.decodeSerializableValue(proxySerializer)
+
+        override fun serialize(encoder: Encoder, value: Float32Vector2D) {
+            val vector = value as? Vector2DImpl ?: Vector2DImpl(value.x, value.y)
+            encoder.encodeSerializableValue(proxySerializer, vector)
+        }
+    }
+
+    public fun vector(x: Float, y: Float): Float32Vector2D =
+        Vector2DImpl(x, y)
+
+    public fun vector(x: Number, y: Number): Float32Vector2D =
+        vector(x.toFloat(), y.toFloat())
+
+    override val zero: Float32Vector2D by lazy { vector(0f, 0f) }
+
+    override fun norm(arg: Vector2D<Float32>): Float32 = sqrt(arg.x.pow(2) + arg.y.pow(2))
+
+    public fun Vector2D<Float32>.norm(): Float32 = norm(this)
+
+    override fun Vector2D<Float32>.unaryMinus(): Float32Vector2D = vector(-x, -y)
+
+    override fun Vector2D<Float32>.distanceTo(other: Vector2D<Float32>): Float32 = (this - other).norm()
+
+    override fun add(left: Vector2D<Float32>, right: Vector2D<Float32>): Float32Vector2D =
+        vector(left.x + right.x, left.y + right.y)
+
+    override fun scale(a: Vector2D<Float32>, value: Double): Float32Vector2D =
+        vector(a.x * value, a.y * value)
+
+    override fun Vector2D<Float32>.dot(other: Vector2D<Float32>): Double =
+        (x * other.x + y * other.y).toDouble()
+
+    public val xAxis: Float32Vector2D = vector(1.0, 0.0)
+    public val yAxis: Float32Vector2D = vector(0.0, 1.0)
+
+    override val defaultPrecision: Float32 = 1e-3f
+
+    override val bufferFactory: MutableBufferFactory<Vector2D<Float32>> = MutableBufferFactory()
+}
+
+public fun Float32Vector2D(x: Number, y: Number): Float32Vector2D = Float32Space2D.vector(x, y)
+
+public val Float32Field.euclidean2D: Float32Space2D get() = Float32Space2D
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Float64Space2D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Float64Space2D.kt
new file mode 100644
index 000000000..3925f8195
--- /dev/null
+++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean2d/Float64Space2D.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.geometry.euclidean2d
+
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.descriptors.SerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
+import space.kscience.kmath.geometry.GeometrySpace
+import space.kscience.kmath.geometry.Vector2D
+import space.kscience.kmath.operations.Float64Field
+import space.kscience.kmath.operations.ScaleOperations
+import space.kscience.kmath.structures.Float64
+import space.kscience.kmath.structures.MutableBufferFactory
+import kotlin.math.pow
+import kotlin.math.sqrt
+
+
+public typealias Float64Vector2D = Vector2D<Float64>
+
+@Deprecated("Use Float64Vector2D", ReplaceWith("Float64Vector2D"))
+public typealias DoubleVector2D = Float64Vector2D
+
+
+/**
+ * 2D Euclidean space
+ */
+public object Float64Space2D : GeometrySpace<Vector2D<Float64>, Float64>, ScaleOperations<Vector2D<Float64>> {
+
+
+    @Serializable
+    @SerialName("Float64Vector2D")
+    private data class Vector2DImpl(
+        override val x: Double,
+        override val y: Double,
+    ) : Float64Vector2D
+
+    public object VectorSerializer : KSerializer<Float64Vector2D> {
+        private val proxySerializer = Vector2DImpl.serializer()
+        override val descriptor: SerialDescriptor get() = proxySerializer.descriptor
+
+        override fun deserialize(decoder: Decoder): Float64Vector2D = decoder.decodeSerializableValue(proxySerializer)
+
+        override fun serialize(encoder: Encoder, value: Float64Vector2D) {
+            val vector = value as? Vector2DImpl ?: Vector2DImpl(value.x, value.y)
+            encoder.encodeSerializableValue(proxySerializer, vector)
+        }
+    }
+
+    public fun vector(x: Number, y: Number): Float64Vector2D = Vector2DImpl(x.toDouble(), y.toDouble())
+
+    override val zero: Float64Vector2D by lazy { vector(0.0, 0.0) }
+
+    override fun norm(arg: Vector2D<Float64>): Double = sqrt(arg.x.pow(2) + arg.y.pow(2))
+
+    override fun Vector2D<Float64>.unaryMinus(): Float64Vector2D = vector(-x, -y)
+
+    override fun Vector2D<Float64>.distanceTo(other: Vector2D<Float64>): Double = norm(this - other)
+    override fun add(left: Vector2D<Float64>, right: Vector2D<Float64>): Float64Vector2D =
+        vector(left.x + right.x, left.y + right.y)
+
+    override fun scale(a: Vector2D<Float64>, value: Double): Float64Vector2D = vector(a.x * value, a.y * value)
+    override fun Vector2D<Float64>.dot(other: Vector2D<Float64>): Double = x * other.x + y * other.y
+
+    public val xAxis: Float64Vector2D = vector(1.0, 0.0)
+    public val yAxis: Float64Vector2D = vector(0.0, 1.0)
+
+    override val defaultPrecision: Double = 1e-6
+
+    override val bufferFactory: MutableBufferFactory<Vector2D<Float64>> = MutableBufferFactory()
+}
+
+public fun Float64Vector2D(x: Number, y: Number): Float64Vector2D = Float64Space2D.vector(x, y)
+
+public val Float64Vector2D.r: Float64 get() = Float64Space2D.norm(this)
+
+public val Float64Field.euclidean2D: Float64Space2D get() = Float64Space2D
\ No newline at end of file
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/Float32Space3D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/Float32Space3D.kt
new file mode 100644
index 000000000..ad61a7b77
--- /dev/null
+++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/Float32Space3D.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.geometry.euclidean3d
+
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.descriptors.SerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
+import space.kscience.kmath.geometry.GeometrySpace
+import space.kscience.kmath.geometry.Vector3D
+import space.kscience.kmath.operations.Float32Field
+import space.kscience.kmath.structures.Float32
+import space.kscience.kmath.structures.MutableBufferFactory
+import kotlin.math.pow
+import kotlin.math.sqrt
+
+
+public typealias Float32Vector3D = Vector3D<Float>
+
+
+public object Float32Space3D : GeometrySpace<Vector3D<Float32>, Float32> {
+
+    @Serializable
+    @SerialName("Float32Vector3D")
+    private data class Vector3DImpl(
+        override val x: Float,
+        override val y: Float,
+        override val z: Float,
+    ) : Float32Vector3D
+
+    public object VectorSerializer : KSerializer<Float32Vector3D> {
+        private val proxySerializer = Vector3DImpl.serializer()
+        override val descriptor: SerialDescriptor get() = proxySerializer.descriptor
+
+        override fun deserialize(decoder: Decoder): Float32Vector3D = decoder.decodeSerializableValue(proxySerializer)
+
+        override fun serialize(encoder: Encoder, value: Float32Vector3D) {
+            val vector = value as? Vector3DImpl ?: Vector3DImpl(value.x, value.y, value.z)
+            encoder.encodeSerializableValue(proxySerializer, vector)
+        }
+    }
+
+    public fun vector(x: Float, y: Float, z: Float): Float32Vector3D =
+        Vector3DImpl(x, y, z)
+
+    public fun vector(x: Number, y: Number, z: Number): Float32Vector3D =
+        vector(x.toFloat(), y.toFloat(), z.toFloat())
+
+    override val zero: Float32Vector3D by lazy { vector(0.0, 0.0, 0.0) }
+
+    override fun norm(arg: Vector3D<Float32>): Float32 = sqrt(arg.x.pow(2) + arg.y.pow(2) + arg.z.pow(2))
+
+    public fun Vector3D<Float32>.norm(): Float32 = norm(this)
+
+    override fun Vector3D<Float32>.unaryMinus(): Float32Vector3D = vector(-x, -y, -z)
+
+    override fun Vector3D<Float32>.distanceTo(other: Vector3D<Float32>): Float32 = (this - other).norm()
+
+    override fun add(left: Vector3D<Float32>, right: Vector3D<Float32>): Float32Vector3D =
+        vector(left.x + right.x, left.y + right.y, left.z + right.z)
+
+    override fun scale(a: Vector3D<Float32>, value: Double): Float32Vector3D =
+        vector(a.x * value, a.y * value, a.z * value)
+
+    override fun Vector3D<Float32>.dot(other: Vector3D<Float32>): Double =
+        (x * other.x + y * other.y + z * other.z).toDouble()
+
+    /**
+     * Compute vector product of [first] and [second]. The basis is assumed to be right-handed.
+     */
+    public fun vectorProduct(
+        first: Float32Vector3D,
+        second: Float32Vector3D,
+    ): Float32Vector3D {
+        var x = 0.0
+        var y = 0.0
+        var z = 0.0
+
+        for (j in (0..2)) {
+            for (k in (0..2)) {
+                x += leviCivita(0, j, k) * first[j] * second[k]
+                y += leviCivita(1, j, k) * first[j] * second[k]
+                z += leviCivita(2, j, k) * first[j] * second[k]
+            }
+        }
+
+        return vector(x, y, z)
+    }
+
+    /**
+     * Vector product in a right-handed basis
+     */
+    public infix fun Float32Vector3D.cross(other: Float32Vector3D): Float32Vector3D = vectorProduct(this, other)
+
+    public val xAxis: Float32Vector3D = vector(1.0, 0.0, 0.0)
+    public val yAxis: Float32Vector3D = vector(0.0, 1.0, 0.0)
+    public val zAxis: Float32Vector3D = vector(0.0, 0.0, 1.0)
+
+    override val defaultPrecision: Float32 = 1e-3f
+
+    override val bufferFactory: MutableBufferFactory<Vector3D<Float32>> = MutableBufferFactory()
+}
+
+public fun Float32Vector3D(x: Number, y: Number, z: Number): Float32Vector3D = Float32Space3D.vector(x, y, z)
+
+public val Float32Field.euclidean3D: Float32Space3D get() = Float32Space3D
\ No newline at end of file
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/Float64Space3D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/Float64Space3D.kt
new file mode 100644
index 000000000..fa07190bb
--- /dev/null
+++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/Float64Space3D.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.geometry.euclidean3d
+
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.descriptors.SerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
+import space.kscience.kmath.geometry.GeometrySpace
+import space.kscience.kmath.geometry.Vector3D
+import space.kscience.kmath.linear.Float64LinearSpace
+import space.kscience.kmath.operations.Float64Field
+import space.kscience.kmath.structures.Float64
+import space.kscience.kmath.structures.MutableBufferFactory
+import kotlin.math.pow
+import kotlin.math.sqrt
+
+internal fun leviCivita(i: Int, j: Int, k: Int): Int = when {
+    // even permutation
+    i == 0 && j == 1 && k == 2 -> 1
+    i == 1 && j == 2 && k == 0 -> 1
+    i == 2 && j == 0 && k == 1 -> 1
+    // odd permutations
+    i == 2 && j == 1 && k == 0 -> -1
+    i == 0 && j == 2 && k == 1 -> -1
+    i == 1 && j == 0 && k == 2 -> -1
+
+    else -> 0
+}
+
+public typealias Float64Vector3D = Vector3D<Float64>
+
+@Deprecated("Use Float64Vector3D", ReplaceWith("Float64Vector3D"))
+public typealias DoubleVector3D = Float64Vector3D
+
+
+public object Float64Space3D : GeometrySpace<Vector3D<Float64>, Double> {
+
+    public val linearSpace: Float64LinearSpace = Float64LinearSpace
+
+    @Serializable
+    @SerialName("Float64Vector3D")
+    private data class Vector3DImpl(
+        override val x: Double,
+        override val y: Double,
+        override val z: Double,
+    ) : Float64Vector3D
+
+    public object VectorSerializer : KSerializer<Float64Vector3D> {
+        private val proxySerializer = Vector3DImpl.serializer()
+        override val descriptor: SerialDescriptor get() = proxySerializer.descriptor
+
+        override fun deserialize(decoder: Decoder): Float64Vector3D = decoder.decodeSerializableValue(proxySerializer)
+
+        override fun serialize(encoder: Encoder, value: Float64Vector3D) {
+            val vector = value as? Vector3DImpl ?: Vector3DImpl(value.x, value.y, value.z)
+            encoder.encodeSerializableValue(proxySerializer, vector)
+        }
+    }
+
+    public fun vector(x: Double, y: Double, z: Double): Float64Vector3D =
+        Vector3DImpl(x, y, z)
+
+    public fun vector(x: Number, y: Number, z: Number): Float64Vector3D =
+        vector(x.toDouble(), y.toDouble(), z.toDouble())
+
+    override val zero: Float64Vector3D by lazy { vector(0.0, 0.0, 0.0) }
+
+    override fun norm(arg: Vector3D<Float64>): Double = sqrt(arg.x.pow(2) + arg.y.pow(2) + arg.z.pow(2))
+
+    public fun Vector3D<Float64>.norm(): Double = norm(this)
+
+    override fun Vector3D<Float64>.unaryMinus(): Float64Vector3D = vector(-x, -y, -z)
+
+    override fun Vector3D<Float64>.distanceTo(other: Vector3D<Float64>): Double = (this - other).norm()
+
+    override fun add(left: Vector3D<Float64>, right: Vector3D<Float64>): Float64Vector3D =
+        vector(left.x + right.x, left.y + right.y, left.z + right.z)
+
+    override fun scale(a: Vector3D<Float64>, value: Double): Float64Vector3D =
+        vector(a.x * value, a.y * value, a.z * value)
+
+    override fun Vector3D<Float64>.dot(other: Vector3D<Float64>): Double =
+        x * other.x + y * other.y + z * other.z
+
+    /**
+     * Compute vector product of [first] and [second]. The basis is assumed to be right-handed.
+     */
+    public fun vectorProduct(
+        first: Vector3D<Float64>,
+        second: Vector3D<Float64>,
+    ): Float64Vector3D {
+        var x = 0.0
+        var y = 0.0
+        var z = 0.0
+
+        for (j in (0..2)) {
+            for (k in (0..2)) {
+                x += leviCivita(0, j, k) * first[j] * second[k]
+                y += leviCivita(1, j, k) * first[j] * second[k]
+                z += leviCivita(2, j, k) * first[j] * second[k]
+            }
+        }
+
+        return vector(x, y, z)
+    }
+
+    /**
+     * Vector product with the right basis
+     */
+    public infix fun Vector3D<Float64>.cross(other: Vector3D<Float64>): Vector3D<Double> = vectorProduct(this, other)
+
+    public val xAxis: Float64Vector3D = vector(1.0, 0.0, 0.0)
+    public val yAxis: Float64Vector3D = vector(0.0, 1.0, 0.0)
+    public val zAxis: Float64Vector3D = vector(0.0, 0.0, 1.0)
+
+    override val defaultPrecision: Double = 1e-6
+
+    override val bufferFactory: MutableBufferFactory<Vector3D<Float64>> = MutableBufferFactory()
+}
+
+@Suppress("UnusedReceiverParameter")
+public val Float64Field.euclidean3D: Float64Space3D get() = Float64Space3D
+
+
+public val Vector3D<Float64>.r: Double get() = Float64Space3D.norm(this)
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/rotations3D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/rotations3D.kt
new file mode 100644
index 000000000..cebad79a2
--- /dev/null
+++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/euclidean3d/rotations3D.kt
@@ -0,0 +1,364 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.geometry.euclidean3d
+
+import space.kscience.kmath.UnstableKMathAPI
+import space.kscience.kmath.complex.*
+import space.kscience.kmath.geometry.*
+import space.kscience.kmath.linear.LinearSpace
+import space.kscience.kmath.linear.Matrix
+import space.kscience.kmath.linear.linearSpace
+import space.kscience.kmath.linear.matrix
+import space.kscience.kmath.operations.Float64Field
+import space.kscience.kmath.structures.Float64
+import kotlin.math.*
+
+public operator fun Quaternion.times(other: Quaternion): Quaternion = QuaternionAlgebra.multiply(this, other)
+
+public operator fun Quaternion.div(other: Quaternion): Quaternion = QuaternionAlgebra.divide(this, other)
+
+public fun Quaternion.power(number: Number): Quaternion = QuaternionAlgebra.power(this, number)
+
+/**
+ * Linear interpolation between [from] and [to] in spherical space
+ */
+public fun QuaternionAlgebra.slerp(from: Quaternion, to: Quaternion, fraction: Double): Quaternion =
+    (to / from).pow(fraction) * from
+
+public fun QuaternionAlgebra.angleBetween(q1: Quaternion, q2: Quaternion): Angle = (q1.conjugate * q2).theta
+
+public infix fun Quaternion.dot(other: Quaternion): Double = w * other.w + x * other.x + y * other.y + z * other.z
+
+
+/**
+ * Represent a vector as quaternion with zero a rotation angle.
+ */
+internal fun Vector3D<Float64>.asQuaternion(): Quaternion = Quaternion(0.0, x, y, z)
+
+
+/**
+ * Angle in radians denoted by this quaternion rotation
+ */
+public val Quaternion.theta: Radians get() = (kotlin.math.acos(normalized().w) * 2).radians
+
+/**
+ * Create a normalized Quaternion from rotation angle and rotation vector
+ */
+public fun Quaternion.Companion.fromRotation(theta: Angle, vector: Float64Vector3D): Quaternion {
+    val s = sin(theta / 2)
+    val c = cos(theta / 2)
+    val norm = with(Float64Space3D) { vector.norm() }
+    return Quaternion(c, vector.x * s / norm, vector.y * s / norm, vector.z * s / norm)
+}
+
+/**
+ * An axis of quaternion rotation
+ */
+public val Quaternion.vector: Float64Vector3D
+    get() {
+        return object : Float64Vector3D {
+            private val sint2 = sqrt(1 - w * w)
+            override val x: Double get() = this@vector.x / sint2
+            override val y: Double get() = this@vector.y / sint2
+            override val z: Double get() = this@vector.z / sint2
+            override fun toString(): String = listOf(x, y, z).toString()
+        }
+    }
+
+/**
+ * Rotate a vector in a [Float64Space3D] with [quaternion]
+ */
+public fun Float64Space3D.rotate(vector: Vector3D<Float64>, quaternion: Quaternion): Float64Vector3D =
+    with(QuaternionAlgebra) {
+        val p = vector.asQuaternion()
+        (quaternion * p * quaternion.reciprocal).vector
+    }
+
+/**
+ * Use a composition of quaternions to create a rotation
+ */
+@UnstableKMathAPI
+public fun Float64Space3D.rotate(
+    vector: Float64Vector3D,
+    composition: QuaternionAlgebra.() -> Quaternion,
+): Float64Vector3D =
+    rotate(vector, QuaternionAlgebra.composition())
+
+/**
+ * Rotate a [Float64] vector in 3D space with a rotation matrix
+ */
+public fun Float64Space3D.rotate(vector: Float64Vector3D, matrix: Matrix<Double>): Vector3D<Float64> {
+    require(matrix.colNum == 3 && matrix.rowNum == 3) { "Square 3x3 rotation matrix is required" }
+    return with(linearSpace) { (matrix dot vector).asVector3D() }
+}
+
+/**
+ * Convert a [Quaternion] to a rotation matrix
+ */
+@OptIn(UnstableKMathAPI::class)
+public fun Quaternion.toRotationMatrix(
+    linearSpace: LinearSpace<Double, *> = Float64Field.linearSpace,
+): Matrix<Double> {
+    val s = QuaternionAlgebra.norm(this).pow(-2)
+    return linearSpace.matrix(3, 3)(
+        1.0 - 2 * s * (y * y + z * z), 2 * s * (x * y - z * w), 2 * s * (x * z + y * w),
+        2 * s * (x * y + z * w), 1.0 - 2 * s * (x * x + z * z), 2 * s * (y * z - x * w),
+        2 * s * (x * z - y * w), 2 * s * (y * z + x * w), 1.0 - 2 * s * (x * x + y * y)
+    )
+}
+
+/**
+ * Convert a quaternion to a rotation matrix
+ *
+ * taken from https://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
+ */
+public fun Quaternion.Companion.fromRotationMatrix(matrix: Matrix<Double>): Quaternion {
+    require(matrix.colNum == 3 && matrix.rowNum == 3) { "Rotation matrix should be 3x3 but is ${matrix.rowNum}x${matrix.colNum}" }
+    val trace = matrix[0, 0] + matrix[1, 1] + matrix[2, 2]
+
+    return if (trace > 0) {
+        val s = sqrt(trace + 1.0) * 2 // S=4*qw
+        Quaternion(
+            w = 0.25 * s,
+            x = (matrix[2, 1] - matrix[1, 2]) / s,
+            y = (matrix[0, 2] - matrix[2, 0]) / s,
+            z = (matrix[1, 0] - matrix[0, 1]) / s,
+        )
+    } else if ((matrix[0, 0] > matrix[1, 1]) && (matrix[0, 0] > matrix[2, 2])) {
+        val s = sqrt(1.0 + matrix[0, 0] - matrix[1, 1] - matrix[2, 2]) * 2 // S=4*qx
+        Quaternion(
+            w = (matrix[2, 1] - matrix[1, 2]) / s,
+            x = 0.25 * s,
+            y = (matrix[0, 1] + matrix[1, 0]) / s,
+            z = (matrix[0, 2] + matrix[2, 0]) / s,
+        )
+    } else if (matrix[1, 1] > matrix[2, 2]) {
+        val s = sqrt(1.0 + matrix[1, 1] - matrix[0, 0] - matrix[2, 2]) * 2 // S=4*qy
+        Quaternion(
+            w = (matrix[0, 2] - matrix[2, 0]) / s,
+            x = (matrix[0, 1] + matrix[1, 0]) / s,
+            y = 0.25 * s,
+            z = (matrix[1, 2] + matrix[2, 1]) / s,
+        )
+    } else {
+        val s = sqrt(1.0 + matrix[2, 2] - matrix[0, 0] - matrix[1, 1]) * 2 // S=4*qz
+        Quaternion(
+            w = (matrix[1, 0] - matrix[0, 1]) / s,
+            x = (matrix[0, 2] + matrix[2, 0]) / s,
+            y = (matrix[1, 2] + matrix[2, 1]) / s,
+            z = 0.25 * s,
+        )
+    }
+}
+
+public enum class RotationOrder {
+    // proper Euler
+    XZX,
+    XYX,
+    YXY,
+    YZY,
+    ZYZ,
+    ZXZ,
+
+    //Tait–Bryan
+    XZY,
+    XYZ,
+    YXZ,
+    YZX,
+    ZYX,
+    ZXY
+}
+
+/**
+ * Create a quaternion from Euler angles
+ *
+ * Based on https://github.com/mrdoob/three.js/blob/master/src/math/Quaternion.js
+ */
+public fun Quaternion.Companion.fromEuler(
+    a: Angle,
+    b: Angle,
+    c: Angle,
+    rotationOrder: RotationOrder,
+): Quaternion {
+    val c1 = cos(a / 2)
+    val c2 = cos(b / 2)
+    val c3 = cos(c / 2)
+
+    val s1 = sin(a / 2)
+    val s2 = sin(b / 2)
+    val s3 = sin(c / 2)
+
+    return when (rotationOrder) {
+
+        RotationOrder.XYZ -> Quaternion(
+            c1 * c2 * c3 - s1 * s2 * s3,
+            s1 * c2 * c3 + c1 * s2 * s3,
+            c1 * s2 * c3 - s1 * c2 * s3,
+            c1 * c2 * s3 + s1 * s2 * c3
+        )
+
+        RotationOrder.YXZ -> Quaternion(
+            c1 * c2 * c3 + s1 * s2 * s3,
+            s1 * c2 * c3 + c1 * s2 * s3,
+            c1 * s2 * c3 - s1 * c2 * s3,
+            c1 * c2 * s3 - s1 * s2 * c3
+        )
+
+        RotationOrder.ZXY -> Quaternion(
+            c1 * c2 * c3 - s1 * s2 * s3,
+            s1 * c2 * c3 - c1 * s2 * s3,
+            c1 * s2 * c3 + s1 * c2 * s3,
+            c1 * c2 * s3 + s1 * s2 * c3
+        )
+
+
+        RotationOrder.ZYX -> Quaternion(
+            c1 * c2 * c3 + s1 * s2 * s3,
+            s1 * c2 * c3 - c1 * s2 * s3,
+            c1 * s2 * c3 + s1 * c2 * s3,
+            c1 * c2 * s3 - s1 * s2 * c3
+        )
+
+        RotationOrder.YZX -> Quaternion(
+            c1 * c2 * c3 - s1 * s2 * s3,
+            s1 * c2 * c3 + c1 * s2 * s3,
+            c1 * s2 * c3 + s1 * c2 * s3,
+            c1 * c2 * s3 - s1 * s2 * c3
+        )
+
+        RotationOrder.XZY -> Quaternion(
+            c1 * c2 * c3 + s1 * s2 * s3,
+            s1 * c2 * c3 - c1 * s2 * s3,
+            c1 * s2 * c3 - s1 * c2 * s3,
+            c1 * c2 * s3 + s1 * s2 * c3
+        )
+
+        else -> TODO("Proper Euler rotation orders are not supported yet")
+    }
+}
+
+/**
+ * A vector consisting of angles
+ */
+public data class AngleVector(override val x: Angle, override val y: Angle, override val z: Angle) : Vector3D<Angle> {
+    public companion object
+}
+
+public fun Quaternion.Companion.fromEuler(
+    angles: AngleVector,
+    rotationOrder: RotationOrder,
+): Quaternion = fromEuler(angles.x, angles.y, angles.z, rotationOrder)
+
+/**
+ * Based on https://github.com/mrdoob/three.js/blob/master/src/math/Euler.js
+ */
+public fun AngleVector.Companion.fromRotationMatrix(
+    matrix: Matrix<Double>,
+    rotationOrder: RotationOrder,
+    gimbaldLockThreshold: Double = 0.9999999,
+): AngleVector = when (rotationOrder) {
+
+    RotationOrder.XYZ -> {
+        if (abs(matrix[0, 2]) < gimbaldLockThreshold) {
+            AngleVector(
+                atan2(-matrix[1, 2], matrix[2, 2]).radians,
+                asin(matrix[0, 2].coerceIn(-1.0, 1.0)).radians,
+                atan2(-matrix[0, 1], matrix[0, 0]).radians
+            )
+
+        } else {
+            AngleVector(
+                atan2(matrix[2, 1], matrix[1, 1]).radians,
+                asin(matrix[0, 2].coerceIn(-1.0, 1.0)).radians,
+                Angle.zero
+            )
+        }
+    }
+
+    RotationOrder.YXZ -> {
+        if (abs(matrix[1, 2]) < gimbaldLockThreshold) {
+            AngleVector(
+                x = asin(-matrix[1, 2].coerceIn(-1.0, 1.0)).radians,
+                y = atan2(matrix[0, 2], matrix[2, 2]).radians,
+                z = atan2(matrix[1, 0], matrix[1, 1]).radians,
+            )
+        } else {
+            AngleVector(
+                x = asin(-matrix[1, 2].coerceIn(-1.0, 1.0)).radians,
+                y = atan2(-matrix[2, 0], matrix[0, 0]).radians,
+                z = Angle.zero,
+            )
+
+        }
+    }
+
+    RotationOrder.ZXY -> {
+        if (abs(matrix[2, 1]) < gimbaldLockThreshold) {
+            AngleVector(
+                x = asin(matrix[2, 1].coerceIn(-1.0, 1.0)).radians,
+                y = atan2(-matrix[2, 0], matrix[2, 2]).radians,
+                z = atan2(-matrix[0, 1], matrix[1, 1]).radians,
+            )
+
+        } else {
+            AngleVector(
+                x = asin(matrix[2, 1].coerceIn(-1.0, 1.0)).radians,
+                y = Angle.zero,
+                z = atan2(matrix[1, 0], matrix[0, 0]).radians,
+            )
+        }
+    }
+
+    RotationOrder.ZYX -> {
+        if (abs(matrix[2, 0]) < gimbaldLockThreshold) {
+            AngleVector(
+                x = atan2(matrix[2, 1], matrix[2, 2]).radians,
+                y = asin(-matrix[2, 0].coerceIn(-1.0, 1.0)).radians,
+                z = atan2(matrix[1, 0], matrix[0, 0]).radians,
+            )
+        } else {
+            AngleVector(
+                x = Angle.zero,
+                y = asin(-matrix[2, 0].coerceIn(-1.0, 1.0)).radians,
+                z = atan2(-matrix[0, 1], matrix[1, 1]).radians,
+            )
+        }
+    }
+
+    RotationOrder.YZX -> {
+        if (abs(matrix[1, 0]) < gimbaldLockThreshold) {
+            AngleVector(
+                x = atan2(-matrix[1, 2], matrix[1, 1]).radians,
+                y = atan2(-matrix[2, 0], matrix[0, 0]).radians,
+                z = asin(matrix[1, 0].coerceIn(-1.0, 1.0)).radians,
+            )
+        } else {
+            AngleVector(
+                x = Angle.zero,
+                y = atan2(matrix[0, 2], matrix[2, 2]).radians,
+                z = asin(matrix[1, 0].coerceIn(-1.0, 1.0)).radians,
+            )
+        }
+    }
+
+    RotationOrder.XZY -> {
+        if (abs(matrix[0, 1]) < gimbaldLockThreshold) {
+            AngleVector(
+                x = atan2(matrix[2, 1], matrix[1, 1]).radians,
+                y = atan2(matrix[0, 2], matrix[0, 0]).radians,
+                z = asin(-matrix[0, 1].coerceIn(-1.0, 1.0)).radians,
+            )
+        } else {
+            AngleVector(
+                x = atan2(-matrix[1, 2], matrix[2, 2]).radians,
+                y = Angle.zero,
+                z = asin(-matrix[0, 1].coerceIn(-1.0, 1.0)).radians,
+            )
+        }
+    }
+
+    else -> TODO("Proper Euler rotation orders are not supported yet")
+}
\ No newline at end of file
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/floatPrecision.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/floatPrecision.kt
deleted file mode 100644
index ea46ab90f..000000000
--- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/floatPrecision.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2018-2023 KMath contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package space.kscience.kmath.geometry
-
-import space.kscience.kmath.geometry.GeometrySpace.Companion.DEFAULT_PRECISION
-
-/**
- * Float equality within given [precision]
- */
-public fun Double.equalsFloat(other: Double, precision: Double = DEFAULT_PRECISION): Boolean =
-    kotlin.math.abs(this - other) < precision
-
-/**
- * Float equality within given [precision]
- */
-public fun Double.equalsFloat(other: Float, precision: Double = DEFAULT_PRECISION): Boolean =
-    kotlin.math.abs(this - other) < precision
-
-/**
- * Vector equality within given [precision] (using [GeometrySpace.norm] provided by the space
- */
-public fun <V : Vector> V.equalsVector(
-    space: GeometrySpace<V>,
-    other: V,
-    precision: Double = DEFAULT_PRECISION,
-): Boolean = with(space) {
-    norm(this@equalsVector - other) < precision
-}
-
-/**
- * Vector equality using Euclidian L2 norm and given [precision]
- */
-public fun Float64Vector2D.equalsVector(
-    other: Float64Vector2D,
-    precision: Double = DEFAULT_PRECISION,
-): Boolean = equalsVector(Euclidean2DSpace, other, precision)
-
-/**
- * Vector equality using Euclidian L2 norm and given [precision]
- */
-public fun Float64Vector3D.equalsVector(
-    other: Float64Vector3D,
-    precision: Double = DEFAULT_PRECISION,
-): Boolean = equalsVector(Euclidean3DSpace, other, precision)
-
-/**
- * Line equality using [GeometrySpace.norm] provided by the [space] and given [precision]
- */
-public fun <V : Vector> LineSegment<V>.equalsLine(
-    space: GeometrySpace<V>,
-    other: LineSegment<V>,
-    precision: Double = DEFAULT_PRECISION,
-): Boolean = begin.equalsVector(space, other.begin, precision) && end.equalsVector(space, other.end, precision)
\ No newline at end of file
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/projections.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/projections.kt
index c5c3487a1..e3f6bb803 100644
--- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/projections.kt
+++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/projections.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -12,7 +12,7 @@ package space.kscience.kmath.geometry
  * @param vector to project
  * @param line line to which vector should be projected
  */
-public fun <V : Vector> GeometrySpace<V>.projectToLine(vector: V, line: Line<V>): V = with(line) {
+public fun <V : Any> GeometrySpace<V, *>.projectToLine(vector: V, line: Line<V>): V = with(line) {
     start + (direction dot (vector - start)) / (direction dot direction) * direction
 }
 
@@ -23,5 +23,5 @@ public fun <V : Vector> GeometrySpace<V>.projectToLine(vector: V, line: Line<V>)
  * @param normal normal (perpendicular) vector to a hyper-plane to which vector should be projected
  * @param base point belonging to a hyper-plane to which vector should be projected
  */
-public fun <V : Vector> GeometrySpace<V>.projectAlong(vector: V, normal: V, base: V): V =
+public fun <V : Any> GeometrySpace<V, *>.projectAlong(vector: V, normal: V, base: V): V =
     vector + normal * ((base - vector) dot normal) / (normal dot normal)
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/quaternionOperations.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/quaternionOperations.kt
new file mode 100644
index 000000000..d45f11a6e
--- /dev/null
+++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/quaternionOperations.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.geometry
+
+import space.kscience.kmath.complex.Quaternion
+import space.kscience.kmath.complex.QuaternionAlgebra
+import space.kscience.kmath.complex.conjugate
+import space.kscience.kmath.geometry.euclidean3d.theta
+
+public operator fun Quaternion.times(other: Quaternion): Quaternion = QuaternionAlgebra.multiply(this, other)
+
+public operator fun Quaternion.div(other: Quaternion): Quaternion = QuaternionAlgebra.divide(this, other)
+
+public fun Quaternion.power(number: Number): Quaternion = QuaternionAlgebra.power(this, number)
+
+/**
+ * Linear interpolation between [from] and [to] in spherical space
+ */
+public fun QuaternionAlgebra.slerp(from: Quaternion, to: Quaternion, fraction: Double): Quaternion =
+    (to / from).pow(fraction) * from
+
+/**
+ * Scalar angle between two quaternions
+ */
+public fun QuaternionAlgebra.angleBetween(q1: Quaternion, q2: Quaternion): Angle = (q1.conjugate * q2).theta
+
+/**
+ * Euclidean product of two quaternions
+ */
+public infix fun Quaternion.dot(other: Quaternion): Double = w * other.w + x * other.x + y * other.y + z * other.z
\ No newline at end of file
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt
deleted file mode 100644
index 1f3850c7c..000000000
--- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright 2018-2022 KMath contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package space.kscience.kmath.geometry
-
-import space.kscience.kmath.UnstableKMathAPI
-import space.kscience.kmath.complex.Quaternion
-import space.kscience.kmath.complex.QuaternionField
-import space.kscience.kmath.complex.normalized
-import space.kscience.kmath.complex.reciprocal
-import space.kscience.kmath.linear.LinearSpace
-import space.kscience.kmath.linear.Matrix
-import space.kscience.kmath.linear.linearSpace
-import space.kscience.kmath.linear.matrix
-import space.kscience.kmath.operations.DoubleField
-import kotlin.math.pow
-import kotlin.math.sqrt
-
-internal fun DoubleVector3D.toQuaternion(): Quaternion = Quaternion(0.0, x, y, z)
-
-/**
- * Angle in radians denoted by this quaternion rotation
- */
-public val Quaternion.theta: Radians get() = (kotlin.math.acos(normalized().w) * 2).radians
-
-/**
- * Create a normalized Quaternion from rotation angle and rotation vector
- */
-public fun Quaternion.Companion.fromRotation(theta: Angle, vector: DoubleVector3D): Quaternion {
-    val s = sin(theta / 2)
-    val c = cos(theta / 2)
-    val norm = with(Euclidean3DSpace) { vector.norm() }
-    return Quaternion(c, vector.x * s / norm, vector.y * s / norm, vector.z * s / norm)
-}
-
-/**
- * An axis of quaternion rotation
- */
-public val Quaternion.vector: DoubleVector3D
-    get() {
-        return object : DoubleVector3D {
-            private val sint2 = sqrt(1 - w * w)
-            override val x: Double get() = this@vector.x / sint2
-            override val y: Double get() = this@vector.y / sint2
-            override val z: Double get() = this@vector.z / sint2
-            override fun toString(): String = listOf(x, y, z).toString()
-        }
-    }
-
-/**
- * Rotate a vector in a [Euclidean3DSpace]
- */
-public fun Euclidean3DSpace.rotate(vector: DoubleVector3D, q: Quaternion): DoubleVector3D = with(QuaternionField) {
-    val p = vector.toQuaternion()
-    (q * p * q.reciprocal).vector
-}
-
-/**
- * Use a composition of quaternions to create a rotation
- */
-@UnstableKMathAPI
-public fun Euclidean3DSpace.rotate(vector: DoubleVector3D, composition: QuaternionField.() -> Quaternion): DoubleVector3D =
-    rotate(vector, QuaternionField.composition())
-
-public fun Euclidean3DSpace.rotate(vector: DoubleVector3D, matrix: Matrix<Double>): DoubleVector3D {
-    require(matrix.colNum == 3 && matrix.rowNum == 3) { "Square 3x3 rotation matrix is required" }
-    return with(DoubleField.linearSpace) { matrix.dot(vector).asVector3D() }
-}
-
-/**
- * Convert a [Quaternion] to a rotation matrix
- */
-@OptIn(UnstableKMathAPI::class)
-public fun Quaternion.toRotationMatrix(
-    linearSpace: LinearSpace<Double, *> = DoubleField.linearSpace,
-): Matrix<Double> {
-    val s = QuaternionField.norm(this).pow(-2)
-    return linearSpace.matrix(3, 3)(
-        1.0 - 2 * s * (y * y + z * z), 2 * s * (x * y - z * w), 2 * s * (x * z + y * w),
-        2 * s * (x * y + z * w), 1.0 - 2 * s * (x * x + z * z), 2 * s * (y * z - x * w),
-        2 * s * (x * z - y * w), 2 * s * (y * z + x * w), 1.0 - 2 * s * (x * x + y * y)
-    )
-}
-
-/**
- * taken from https://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
- */
-public fun Quaternion.Companion.fromRotationMatrix(matrix: Matrix<Double>): Quaternion {
-    require(matrix.colNum == 3 && matrix.rowNum == 3) { "Rotation matrix should be 3x3 but is ${matrix.rowNum}x${matrix.colNum}" }
-    val trace = matrix[0, 0] + matrix[1, 1] + matrix[2, 2]
-
-    return if (trace > 0) {
-        val s = sqrt(trace + 1.0) * 2 // S=4*qw
-        Quaternion(
-            w = 0.25 * s,
-            x = (matrix[2, 1] - matrix[1, 2]) / s,
-            y = (matrix[0, 2] - matrix[2, 0]) / s,
-            z = (matrix[1, 0] - matrix[0, 1]) / s,
-        )
-    } else if ((matrix[0, 0] > matrix[1, 1]) && (matrix[0, 0] > matrix[2, 2])) {
-        val s = sqrt(1.0 + matrix[0, 0] - matrix[1, 1] - matrix[2, 2]) * 2 // S=4*qx
-        Quaternion(
-            w = (matrix[2, 1] - matrix[1, 2]) / s,
-            x = 0.25 * s,
-            y = (matrix[0, 1] + matrix[1, 0]) / s,
-            z = (matrix[0, 2] + matrix[2, 0]) / s,
-        )
-    } else if (matrix[1, 1] > matrix[2, 2]) {
-        val s = sqrt(1.0 + matrix[1, 1] - matrix[0, 0] - matrix[2, 2]) * 2 // S=4*qy
-        Quaternion(
-            w = (matrix[0, 2] - matrix[2, 0]) / s,
-            x = (matrix[0, 1] + matrix[1, 0]) / s,
-            y = 0.25 * s,
-            z = (matrix[1, 2] + matrix[2, 1]) / s,
-        )
-    } else {
-        val s = sqrt(1.0 + matrix[2, 2] - matrix[0, 0] - matrix[1, 1]) * 2 // S=4*qz
-        Quaternion(
-            w = (matrix[1, 0] - matrix[0, 1]) / s,
-            x = (matrix[0, 2] + matrix[2, 0]) / s,
-            y = (matrix[1, 2] + matrix[2, 1]) / s,
-            z = 0.25 * s,
-        )
-    }
-}
-
-public enum class RotationOrder {
-    // proper Euler
-    XZX,
-    XYX,
-    YXY,
-    YZY,
-    ZYZ,
-    ZXZ,
-
-    //Tait–Bryan
-    XZY,
-    XYZ,
-    YXZ,
-    YZX,
-    ZYX,
-    ZXY
-}
-
-/**
- * Based on https://github.com/mrdoob/three.js/blob/master/src/math/Quaternion.js
- */
-public fun Quaternion.Companion.fromEuler(
-    a: Angle,
-    b: Angle,
-    c: Angle,
-    rotationOrder: RotationOrder,
-): Quaternion {
-    val c1 = cos (a / 2)
-    val c2 = cos (b / 2)
-    val c3 = cos (c / 2)
-
-    val s1 = sin (a / 2)
-    val s2 = sin (b / 2)
-    val s3 = sin (c / 2)
-
-    return when (rotationOrder) {
-
-        RotationOrder.XYZ -> Quaternion(
-            c1 * c2 * c3 - s1 * s2 * s3,
-            s1 * c2 * c3 + c1 * s2 * s3,
-            c1 * s2 * c3 - s1 * c2 * s3,
-            c1 * c2 * s3 + s1 * s2 * c3
-        )
-
-        RotationOrder.YXZ -> Quaternion(
-            c1 * c2 * c3 + s1 * s2 * s3,
-            s1 * c2 * c3 + c1 * s2 * s3,
-            c1 * s2 * c3 - s1 * c2 * s3,
-            c1 * c2 * s3 - s1 * s2 * c3
-        )
-
-        RotationOrder.ZXY -> Quaternion(
-            c1 * c2 * c3 - s1 * s2 * s3,
-            s1 * c2 * c3 - c1 * s2 * s3,
-            c1 * s2 * c3 + s1 * c2 * s3,
-            c1 * c2 * s3 + s1 * s2 * c3
-        )
-
-
-        RotationOrder.ZYX -> Quaternion(
-            c1 * c2 * c3 + s1 * s2 * s3,
-            s1 * c2 * c3 - c1 * s2 * s3,
-            c1 * s2 * c3 + s1 * c2 * s3,
-            c1 * c2 * s3 - s1 * s2 * c3
-        )
-
-        RotationOrder.YZX -> Quaternion(
-            c1 * c2 * c3 - s1 * s2 * s3,
-            s1 * c2 * c3 + c1 * s2 * s3,
-            c1 * s2 * c3 + s1 * c2 * s3,
-            c1 * c2 * s3 - s1 * s2 * c3
-        )
-
-        RotationOrder.XZY -> Quaternion(
-            c1 * c2 * c3 + s1 * s2 * s3,
-            s1 * c2 * c3 - c1 * s2 * s3,
-            c1 * s2 * c3 - s1 * c2 * s3,
-            c1 * c2 * s3 + s1 * s2 * c3
-        )
-         else -> TODO("Proper Euler rotation orders are not supported yet")
-    }
-}
\ No newline at end of file
diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/vectorPrecision.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/vectorPrecision.kt
new file mode 100644
index 000000000..e8a14d036
--- /dev/null
+++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/vectorPrecision.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.geometry
+
+import space.kscience.kmath.geometry.euclidean2d.Float64Space2D
+import space.kscience.kmath.geometry.euclidean2d.Float64Vector2D
+import space.kscience.kmath.geometry.euclidean3d.Float64Space3D
+import space.kscience.kmath.geometry.euclidean3d.Float64Vector3D
+import space.kscience.kmath.structures.Float64
+
+
+/**
+ * Vector equality within given [precision] (using [GeometrySpace.norm] provided by the space
+ */
+public fun <V : Any, D : Comparable<D>> V.equalsVector(
+    space: GeometrySpace<V, D>,
+    other: V,
+    precision: D = space.defaultPrecision,
+): Boolean = with(space) {
+    norm(this@equalsVector - other) < precision
+}
+
+/**
+ * Vector equality using Euclidian L2 norm and given [precision]
+ */
+public fun Vector2D<Float64>.equalsVector(
+    other: Float64Vector2D,
+    precision: Double = Float64Space2D.defaultPrecision,
+): Boolean = equalsVector(Float64Space2D, other, precision)
+
+/**
+ * Vector equality using Euclidean L2 norm and given [precision]
+ */
+public fun Vector3D<Float64>.equalsVector(
+    other: Float64Vector3D,
+    precision: Double = Float64Space3D.defaultPrecision,
+): Boolean = equalsVector(Float64Space3D, other, precision)
+
+/**
+ * Line equality using [GeometrySpace.norm] provided by the [space] and given [precision]
+ */
+public fun <V : Any, D : Comparable<D>> LineSegment<V>.equalsLine(
+    space: GeometrySpace<V, D>,
+    other: LineSegment<V>,
+    precision: D = space.defaultPrecision,
+): Boolean = begin.equalsVector(space, other.begin, precision) && end.equalsVector(space, other.end, precision)
\ No newline at end of file
diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/AngleTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/AngleTest.kt
index b8086eb75..d5209a1bd 100644
--- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/AngleTest.kt
+++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/AngleTest.kt
@@ -1,3 +1,8 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
 package space.kscience.kmath.geometry
 
 import kotlin.test.Test
diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt
index 22cbee6f0..2ad7c940f 100644
--- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt
+++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt
@@ -1,10 +1,11 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.geometry
 
+import space.kscience.kmath.geometry.euclidean2d.Float64Space2D
 import kotlin.math.sqrt
 import kotlin.test.Test
 import kotlin.test.assertEquals
@@ -12,12 +13,12 @@ import kotlin.test.assertEquals
 internal class Euclidean2DSpaceTest {
     @Test
     fun zero() {
-        assertVectorEquals(Euclidean2DSpace.vector(0.0, 0.0), Euclidean2DSpace.zero)
+        assertVectorEquals(Float64Space2D.vector(0.0, 0.0), Float64Space2D.zero)
     }
 
     @Test
     fun norm() {
-        with(Euclidean2DSpace) {
+        with(Float64Space2D) {
             assertEquals(0.0, norm(zero))
             assertEquals(1.0, norm(vector(1.0, 0.0)))
             assertEquals(sqrt(2.0), norm(vector(1.0, 1.0)))
@@ -27,7 +28,7 @@ internal class Euclidean2DSpaceTest {
 
     @Test
     fun dotProduct() {
-        with(Euclidean2DSpace) {
+        with(Float64Space2D) {
             assertEquals(0.0, zero dot zero)
             assertEquals(0.0, zero dot vector(1.0, 0.0))
             assertEquals(0.0, vector(-2.0, 0.001) dot zero)
@@ -44,7 +45,7 @@ internal class Euclidean2DSpaceTest {
 
     @Test
     fun add() {
-        with(Euclidean2DSpace) {
+        with(Float64Space2D) {
             assertVectorEquals(
                 vector(-2.0, 0.001),
                 vector(-2.0, 0.001) + zero
@@ -58,7 +59,7 @@ internal class Euclidean2DSpaceTest {
 
     @Test
     fun multiply() {
-        with(Euclidean2DSpace) {
+        with(Float64Space2D) {
             assertVectorEquals(vector(-4.0, 0.0), vector(-2.0, 0.0) * 2)
             assertVectorEquals(vector(4.0, 0.0), vector(-2.0, 0.0) * -2)
             assertVectorEquals(vector(300.0, 0.0003), vector(100.0, 0.0001) * 3)
diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt
index 20e112ad1..64bdfcc61 100644
--- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt
+++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt
@@ -1,22 +1,23 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.geometry
 
+import space.kscience.kmath.geometry.euclidean3d.Float64Space3D
 import kotlin.test.Test
 import kotlin.test.assertEquals
 
 internal class Euclidean3DSpaceTest {
     @Test
     fun zero() {
-        assertVectorEquals(Euclidean3DSpace.vector(0.0, 0.0, 0.0), Euclidean3DSpace.zero)
+        assertVectorEquals(Float64Space3D.vector(0.0, 0.0, 0.0), Float64Space3D.zero)
     }
 
     @Test
     fun distance() {
-        with(Euclidean3DSpace) {
+        with(Float64Space3D) {
             assertEquals(0.0, zero.distanceTo(zero))
             assertEquals(1.0, zero.distanceTo(vector(1.0, 0.0, 0.0)))
             assertEquals(kotlin.math.sqrt(5.000001), vector(1.0, -2.0, 0.001).distanceTo(zero))
@@ -31,7 +32,7 @@ internal class Euclidean3DSpaceTest {
 
     @Test
     fun norm() {
-        with(Euclidean3DSpace) {
+        with(Float64Space3D) {
             assertEquals(0.0, zero.norm())
             assertEquals(1.0, vector(1.0, 0.0, 0.0).norm())
             assertEquals(kotlin.math.sqrt(3.0), vector(1.0, 1.0, 1.0).norm())
@@ -41,7 +42,7 @@ internal class Euclidean3DSpaceTest {
 
     @Test
     fun dotProduct() {
-        with(Euclidean3DSpace) {
+        with(Float64Space3D) {
             assertEquals(0.0, zero dot zero)
             assertEquals(0.0, zero dot vector(1.0, 0.0, 0.0))
             assertEquals(0.0, vector(1.0, -2.0, 0.001) dot zero)
@@ -57,7 +58,7 @@ internal class Euclidean3DSpaceTest {
     }
 
     @Test
-    fun add() = with(Euclidean3DSpace) {
+    fun add() = with(Float64Space3D) {
         assertVectorEquals(
             vector(1.0, -2.0, 0.001),
             vector(1.0, -2.0, 0.001) + zero
@@ -69,19 +70,19 @@ internal class Euclidean3DSpaceTest {
     }
 
     @Test
-    fun multiply() = with(Euclidean3DSpace) {
+    fun multiply() = with(Float64Space3D) {
         assertVectorEquals(vector(2.0, -4.0, 0.0), vector(1.0, -2.0, 0.0) * 2)
     }
 
     @Test
-    fun vectorProduct() = with(Euclidean3DSpace) {
+    fun vectorProduct() = with(Float64Space3D) {
         assertVectorEquals(zAxis, vectorProduct(xAxis, yAxis))
         assertVectorEquals(zAxis, xAxis cross yAxis)
         assertVectorEquals(-zAxis, vectorProduct(yAxis, xAxis))
     }
 
     @Test
-    fun doubleVectorProduct() = with(Euclidean3DSpace) {
+    fun doubleVectorProduct() = with(Float64Space3D) {
         val a = vector(1, 2, -3)
         val b = vector(-1, 0, 1)
         val c = vector(4, 5, 6)
diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt
index cc74b06e3..ae4ee84e0 100644
--- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt
+++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt
@@ -1,17 +1,19 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.geometry
 
+import space.kscience.kmath.geometry.euclidean2d.Float64Space2D
+import space.kscience.kmath.geometry.euclidean3d.Float64Space3D
 import kotlin.test.Test
 import kotlin.test.assertTrue
 
 internal class ProjectionAlongTest {
     @Test
     fun projectionIntoYEqualsX() {
-        with(Euclidean2DSpace) {
+        with(Float64Space2D) {
             val normal = vector(-2.0, 2.0)
             val base = vector(2.3, 2.3)
 
@@ -26,7 +28,7 @@ internal class ProjectionAlongTest {
 
     @Test
     fun projectionOntoLine() {
-        with(Euclidean2DSpace) {
+        with(Float64Space2D) {
             val a = 5.0
             val b = -3.0
             val c = -15.0
@@ -42,11 +44,11 @@ internal class ProjectionAlongTest {
     }
 
     @Test
-    fun projectOntoPlane() = with(Euclidean3DSpace){
+    fun projectOntoPlane() = with(Float64Space3D) {
         val normal = vector(1.0, 3.5, 0.07)
         val base = vector(2.0, -0.0037, 11.1111)
 
-        with(Euclidean3DSpace) {
+        with(Float64Space3D) {
             val testDomain = (-10.0..10.0).generateList(0.43)
             for (x in testDomain) {
                 for (y in testDomain) {
diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt
index 7c6c105cf..32bd710c6 100644
--- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt
+++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt
@@ -1,17 +1,19 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.geometry
 
+import space.kscience.kmath.geometry.euclidean2d.Float64Space2D
+import space.kscience.kmath.geometry.euclidean3d.Float64Space3D
 import kotlin.test.Test
 import kotlin.test.assertTrue
 
 internal class ProjectionOntoLineTest {
     @Test
     fun projectionIntoOx() {
-        with(Euclidean2DSpace) {
+        with(Float64Space2D) {
             val ox = Line(zero, vector(1.0, 0.0))
 
             grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) ->
@@ -22,7 +24,7 @@ internal class ProjectionOntoLineTest {
 
     @Test
     fun projectionIntoOy() {
-        with(Euclidean2DSpace) {
+        with(Float64Space2D) {
             val line = Line(zero, vector(0.0, 1.0))
 
             grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) ->
@@ -33,7 +35,7 @@ internal class ProjectionOntoLineTest {
 
     @Test
     fun projectionIntoYEqualsX() {
-        with(Euclidean2DSpace) {
+        with(Float64Space2D) {
             val line = Line(zero, vector(1.0, 1.0))
 
             assertVectorEquals(zero, projectToLine(zero, line))
@@ -47,7 +49,7 @@ internal class ProjectionOntoLineTest {
 
     @Test
     fun projectionOntoLine2d() {
-        with(Euclidean2DSpace) {
+        with(Float64Space2D) {
             val a = 5.0
             val b = -3.0
             val c = -15.0
@@ -62,7 +64,7 @@ internal class ProjectionOntoLineTest {
     }
 
     @Test
-    fun projectionOntoLine3d() = with(Euclidean3DSpace) {
+    fun projectionOntoLine3d() = with(Float64Space3D) {
         val line = Line(
             base = vector(1.0, 3.5, 0.07),
             direction = vector(2.0, -0.0037, 11.1111)
diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt
index 6177382a2..c802470b2 100644
--- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt
+++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt
@@ -1,20 +1,22 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.geometry
 
 import space.kscience.kmath.complex.Quaternion
+import space.kscience.kmath.complex.QuaternionAlgebra
 import space.kscience.kmath.complex.normalized
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.geometry.euclidean3d.*
+import space.kscience.kmath.structures.Float64Buffer
 import space.kscience.kmath.testutils.assertBufferEquals
 import kotlin.test.Test
 
 class RotationTest {
 
     @Test
-    fun differentRotations() = with(Euclidean3DSpace) {
+    fun differentRotations() = with(Float64Space3D) {
         val vector = vector(1.0, 1.0, 1.0)
         val q = Quaternion(1.0, 2.0, -3.0, 4.0).normalized()
         val rotatedByQ = rotate(vector, q)
@@ -25,26 +27,48 @@ class RotationTest {
     }
 
     @Test
-    fun matrixConversion() {
+    fun matrixConversion() = with(QuaternionAlgebra) {
 
         val q = Quaternion(1.0, 2.0, -3.0, 4.0).normalized()
 
         val matrix = q.toRotationMatrix()
 
+        for (ro in listOf(
+            RotationOrder.XYZ,
+            RotationOrder.YXZ,
+            RotationOrder.ZXY,
+            RotationOrder.ZYX,
+            RotationOrder.YZX,
+            RotationOrder.XZY
+        )) {
+            val angles = AngleVector.fromRotationMatrix(matrix, ro)
+
+            val reconstructed = Quaternion.fromEuler(angles, ro)
+
+            if (reconstructed.w > 0) {
+                assertBufferEquals(q, reconstructed)
+            } else {
+                assertBufferEquals(q, -reconstructed)
+            }
+        }
+
         assertBufferEquals(q, Quaternion.fromRotationMatrix(matrix))
     }
 
     @Test
     fun fromRotation() {
-        val q = Quaternion.fromRotation(0.3.radians, Euclidean3DSpace.vector(1.0, 1.0, 1.0))
+        val q = Quaternion.fromRotation(0.3.radians, Float64Space3D.vector(1.0, 1.0, 1.0))
 
-        assertBufferEquals(DoubleBuffer(0.9887711, 0.0862781, 0.0862781, 0.0862781), q)
+        assertBufferEquals(Float64Buffer(0.9887711, 0.0862781, 0.0862781, 0.0862781), q)
     }
 
     @Test
     fun fromEuler() {
         val q = Quaternion.fromEuler(0.1.radians, 0.2.radians, 0.3.radians, RotationOrder.ZXY)
+        assertBufferEquals(Float64Buffer(0.9818562, 0.0342708, 0.1060205, 0.1534393), q)
 
-        assertBufferEquals(DoubleBuffer(0.9818562, 0.0342708, 0.1060205, 0.1534393), q)
+        val q1 = Quaternion.fromEuler(0.1.radians, 0.2.radians, 0.3.radians, RotationOrder.XYZ)
+        assertBufferEquals(Float64Buffer(0.9818562, 0.0640713, 0.0911575, 0.1534393), q1)
     }
+
 }
\ No newline at end of file
diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt
index 0db06f4c8..af886ec29 100644
--- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt
+++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt
@@ -1,17 +1,18 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.geometry
 
 
+import space.kscience.kmath.geometry.euclidean2d.Float64Space2D
 import space.kscience.kmath.operations.toList
 import kotlin.test.Test
 import kotlin.test.assertEquals
 
 internal class Vector2DTest {
-    private val vector = Euclidean2DSpace.vector(1.0, -7.999)
+    private val vector = Float64Space2D.vector(1.0, -7.999)
 
     @Test
     fun size() {
diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt
index 1c8607838..9157f95d8 100644
--- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt
+++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt
@@ -1,16 +1,17 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.geometry
 
+import space.kscience.kmath.geometry.euclidean3d.Float64Space3D
 import space.kscience.kmath.operations.toList
 import kotlin.test.Test
 import kotlin.test.assertEquals
 
 internal class Vector3DTest {
-    private val vector = Euclidean3DSpace.vector(1.0, -7.999, 0.001)
+    private val vector = Float64Space3D.vector(1.0, -7.999, 0.001)
 
     @Test
     fun size() {
diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt
index c62af3cd3..22b58d260 100644
--- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt
+++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt
@@ -1,10 +1,11 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.geometry
 
+import space.kscience.kmath.structures.Float64
 import kotlin.math.abs
 import kotlin.test.assertEquals
 
@@ -17,7 +18,7 @@ fun ClosedRange<Double>.generateList(step: Double): List<Double> = generateSeque
 fun grid(
     xRange: ClosedRange<Double>,
     yRange: ClosedRange<Double>,
-    step: Double
+    step: Double,
 ): List<Pair<Double, Double>> {
     val xs = xRange.generateList(step)
     val ys = yRange.generateList(step)
@@ -25,24 +26,24 @@ fun grid(
     return xs.flatMap { x -> ys.map { y -> x to y } }
 }
 
-fun assertVectorEquals(expected: DoubleVector2D, actual: DoubleVector2D, absoluteTolerance: Double = 1e-6) {
+fun assertVectorEquals(expected: Vector2D<Float64>, actual: Vector2D<Float64>, absoluteTolerance: Double = 1e-3) {
     assertEquals(expected.x, actual.x, absoluteTolerance)
     assertEquals(expected.y, actual.y, absoluteTolerance)
 }
 
-fun assertVectorEquals(expected: DoubleVector3D, actual: DoubleVector3D, absoluteTolerance: Double = 1e-6) {
+fun assertVectorEquals(expected: Vector3D<Float64>, actual: Vector3D<Float64>, absoluteTolerance: Double = 1e-6) {
     assertEquals(expected.x, actual.x, absoluteTolerance)
     assertEquals(expected.y, actual.y, absoluteTolerance)
     assertEquals(expected.z, actual.z, absoluteTolerance)
 }
 
-fun <V : Vector> GeometrySpace<V>.isCollinear(a: V, b: V, absoluteTolerance: Double = 1e-6): Boolean {
+fun <V : Any> GeometrySpace<V, Double>.isCollinear(a: V, b: V, absoluteTolerance: Double = defaultPrecision): Boolean {
     val aDist = a.distanceTo(zero)
     val bDist = b.distanceTo(zero)
-    return abs(aDist) < absoluteTolerance || abs(bDist) < absoluteTolerance || abs(abs((a dot b) / (aDist * bDist)) - 1) < absoluteTolerance
+    return aDist < absoluteTolerance || bDist < absoluteTolerance || abs(abs((a dot b) / (aDist * bDist)) - 1) < absoluteTolerance
 }
 
-fun <V : Vector> GeometrySpace<V>.isOrthogonal(a: V, b: V, absoluteTolerance: Double = 1e-6): Boolean =
+fun <V : Any> GeometrySpace<V, *>.isOrthogonal(a: V, b: V, absoluteTolerance: Double = 1e-6): Boolean =
     abs(a dot b) < absoluteTolerance
 
 fun Double.equalFloat(other: Double, maxFloatDelta: Double = 0.000001):
diff --git a/kmath-geometry/src/jvmMain/kotlin/space/kscience/kmath/geometry/lineExtensions.kt b/kmath-geometry/src/jvmMain/kotlin/space/kscience/kmath/geometry/lineExtensions.kt
index 5fcd2b23e..c263398ea 100644
--- a/kmath-geometry/src/jvmMain/kotlin/space/kscience/kmath/geometry/lineExtensions.kt
+++ b/kmath-geometry/src/jvmMain/kotlin/space/kscience/kmath/geometry/lineExtensions.kt
@@ -1,20 +1,23 @@
 /*
- * Copyright 2018-2021 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 import space.kscience.kmath.geometry.GeometrySpace
 import space.kscience.kmath.geometry.Line
 import space.kscience.kmath.geometry.LineSegment
-import space.kscience.kmath.geometry.Vector
 import space.kscience.kmath.operations.Group
 
 /**
  * Get a line, containing this [LineSegment]
  */
-context(Group<V>) public val <V : Vector> LineSegment<V>.line: Line<V> get() = Line(begin, end - begin)
+context(Group<V>)
+public val <V : Any> LineSegment<V>.line: Line<V>
+    get() = Line(begin, end - begin)
 
 /**
  * Get a length of a line segment
  */
-context(GeometrySpace<V>) public val <V : Vector> LineSegment<V>.length: Double get() = norm(end - begin)
\ No newline at end of file
+context(GeometrySpace<V, D>)
+public val <V : Any, D : Comparable<D>> LineSegment<V>.length: D
+    get() = norm(end - begin)
\ No newline at end of file
diff --git a/kmath-histograms/README.md b/kmath-histograms/README.md
index bc7f0fa5b..5f494310a 100644
--- a/kmath-histograms/README.md
+++ b/kmath-histograms/README.md
@@ -6,19 +6,8 @@
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-histograms:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-histograms:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-histograms:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -27,6 +16,6 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-histograms:0.4.0-dev-1")
+    implementation("space.kscience:kmath-histograms:0.4.0")
 }
 ```
diff --git a/kmath-histograms/build.gradle.kts b/kmath-histograms/build.gradle.kts
index 33704c29e..b7802054a 100644
--- a/kmath-histograms/build.gradle.kts
+++ b/kmath-histograms/build.gradle.kts
@@ -2,10 +2,12 @@ plugins {
     id("space.kscience.gradle.mpp")
 }
 
-kscience{
+kscience {
     jvm()
     js()
     native()
+    wasm()
+    useCoroutines()
 }
 
 //apply(plugin = "kotlinx-atomicfu")
@@ -21,7 +23,6 @@ kotlin.sourceSets {
         dependencies {
             implementation(project(":kmath-for-real"))
             implementation(projects.kmath.kmathStat)
-            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0")
         }
     }
 }
diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt
index 43ed24c70..a931b957d 100644
--- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt
+++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,7 +7,7 @@ package space.kscience.kmath.histogram
 
 import kotlinx.atomicfu.atomic
 import kotlinx.atomicfu.getAndUpdate
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.Group
 
 /**
@@ -18,8 +18,8 @@ public interface Counter<T : Any> {
     public val value: T
 
     public companion object {
-        public fun ofDouble(): ObjectCounter<Double> = ObjectCounter(DoubleField)
-        public fun <T: Any> of(group: Group<T>): ObjectCounter<T> = ObjectCounter(group)
+        public fun ofDouble(): ObjectCounter<Double> = ObjectCounter(Float64Field)
+        public fun <T : Any> of(group: Group<T>): ObjectCounter<T> = ObjectCounter(group)
     }
 }
 
diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt
index a4ae6d935..7f6fb2d26 100644
--- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt
+++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,7 +7,7 @@ package space.kscience.kmath.histogram
 
 import space.kscience.kmath.domains.Domain
 import space.kscience.kmath.linear.Point
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import space.kscience.kmath.structures.asBuffer
 
 /**
@@ -47,7 +47,7 @@ public interface Histogram<in T : Any, out V, out B : Bin<T, V>> {
     }
 }
 
-public interface HistogramBuilder<in T : Any, V : Any> {
+public interface HistogramBuilder<in T, V> {
 
     /**
      * The default value increment for a bin
@@ -61,14 +61,14 @@ public interface HistogramBuilder<in T : Any, V : Any> {
 
 }
 
-public fun <T : Any> HistogramBuilder<T, *>.put(point: Point<out T>): Unit = putValue(point)
+public fun <T> HistogramBuilder<T, *>.put(point: Point<T>): Unit = putValue(point)
 
-public fun <T : Any> HistogramBuilder<T, *>.put(vararg point: T): Unit = put(point.asBuffer())
+public inline fun <reified T> HistogramBuilder<T, *>.put(vararg point: T): Unit = put(point.asList().asBuffer())
 
 public fun HistogramBuilder<Double, *>.put(vararg point: Number): Unit =
-    put(DoubleBuffer(point.map { it.toDouble() }.toDoubleArray()))
+    put(Float64Buffer(point.map { it.toDouble() }.toDoubleArray()))
 
-public fun HistogramBuilder<Double, *>.put(vararg point: Double): Unit = put(DoubleBuffer(point))
+public fun HistogramBuilder<Double, *>.put(vararg point: Double): Unit = put(Float64Buffer(point))
 public fun <T : Any> HistogramBuilder<T, *>.fill(sequence: Iterable<Point<T>>): Unit = sequence.forEach { put(it) }
 
 /**
diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt
index f50610a17..ef72f2630 100644
--- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt
+++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/HistogramND.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/HistogramND.kt
index 5fdc2ffb0..36acd8db5 100644
--- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/HistogramND.kt
+++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/HistogramND.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt
index 154d35350..770fd70a0 100644
--- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt
+++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -12,6 +12,7 @@ import space.kscience.kmath.operations.Ring
 import space.kscience.kmath.operations.ScaleOperations
 import space.kscience.kmath.operations.invoke
 import space.kscience.kmath.structures.Buffer
+import space.kscience.kmath.structures.MutableBufferFactory
 import kotlin.math.floor
 
 @OptIn(UnstableKMathAPI::class)
@@ -46,6 +47,8 @@ public class UniformHistogram1DGroup<V : Any, A>(
     public val startPoint: Double = 0.0,
 ) : Group<Histogram1D<Double, V>>, ScaleOperations<Histogram1D<Double, V>> where A : Ring<V>, A : ScaleOperations<V> {
 
+    override val bufferFactory: MutableBufferFactory<Histogram1D<Double, V>> = MutableBufferFactory()
+
     override val zero: UniformHistogram1D<V> = UniformHistogram1D(this, emptyMap())
 
     /**
diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt
index 61ce450a7..8a914530b 100644
--- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt
+++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -37,11 +37,13 @@ public class UniformHistogramGroupND<V : Any, A : Field<V>>(
         require(!lower.indices.any { upper[it] - lower[it] < 0 }) { "Range for one of axis is not strictly positive" }
     }
 
+    override val bufferFactory: MutableBufferFactory<HistogramND<Double, HyperSquareDomain, V>> = MutableBufferFactory()
+
     public val dimension: Int get() = lower.size
 
     override val shape: ShapeND = ShapeND(IntArray(binNums.size) { binNums[it] + 2 })
 
-    private val binSize = DoubleBuffer(dimension) { (upper[it] - lower[it]) / binNums[it] }
+    private val binSize = Float64Buffer(dimension) { (upper[it] - lower[it]) / binNums[it] }
 
     /**
      * Get internal [StructureND] bin index for given axis
@@ -87,7 +89,7 @@ public class UniformHistogramGroupND<V : Any, A : Field<V>>(
         builder: HistogramBuilder<Double, V>.() -> Unit,
     ): HistogramND<Double, HyperSquareDomain, V> {
         val ndCounter: BufferND<ObjectCounter<V>> =
-            StructureND.buffered(shape) { Counter.of(valueAlgebraND.elementAlgebra) }
+            BufferND(shape) { Counter.of(valueAlgebraND.elementAlgebra) }
         val hBuilder = object : HistogramBuilder<Double, V> {
             override val defaultValue: V get() = valueAlgebraND.elementAlgebra.one
 
@@ -97,7 +99,8 @@ public class UniformHistogramGroupND<V : Any, A : Field<V>>(
             }
         }
         hBuilder.apply(builder)
-        val values: BufferND<V> = BufferND(ndCounter.indices, ndCounter.buffer.mapToBuffer(valueBufferFactory) { it.value })
+        val values: BufferND<V> =
+            BufferND(ndCounter.indices, ndCounter.buffer.mapToBuffer(valueBufferFactory) { it.value })
 
         return HistogramND(this, values)
     }
@@ -128,8 +131,7 @@ public fun <V : Any, A : Field<V>> Histogram.Companion.uniformNDFromRanges(
 
 public fun Histogram.Companion.uniformDoubleNDFromRanges(
     vararg ranges: ClosedFloatingPointRange<Double>,
-): UniformHistogramGroupND<Double, DoubleField> =
-    uniformNDFromRanges(DoubleFieldOpsND, *ranges, bufferFactory = ::DoubleBuffer)
+): UniformHistogramGroupND<Double, Float64Field> = uniformNDFromRanges(Floa64FieldOpsND, *ranges)
 
 
 /**
@@ -147,21 +149,18 @@ public fun <V : Any, A : Field<V>> Histogram.Companion.uniformNDFromRanges(
     bufferFactory: BufferFactory<V> = valueAlgebraND.elementAlgebra.bufferFactory,
 ): UniformHistogramGroupND<V, A> = UniformHistogramGroupND(
     valueAlgebraND,
-    ListBuffer(
-        ranges
-            .map(Pair<ClosedFloatingPointRange<Double>, Int>::first)
-            .map(ClosedFloatingPointRange<Double>::start)
-    ),
-    ListBuffer(
-        ranges
-            .map(Pair<ClosedFloatingPointRange<Double>, Int>::first)
-            .map(ClosedFloatingPointRange<Double>::endInclusive)
-    ),
+    ranges
+        .map(Pair<ClosedFloatingPointRange<Double>, Int>::first)
+        .map(ClosedFloatingPointRange<Double>::start)
+        .asBuffer(),
+    ranges
+        .map(Pair<ClosedFloatingPointRange<Double>, Int>::first)
+        .map(ClosedFloatingPointRange<Double>::endInclusive)
+        .asBuffer(),
     ranges.map(Pair<ClosedFloatingPointRange<Double>, Int>::second).toIntArray(),
     valueBufferFactory = bufferFactory
 )
 
 public fun Histogram.Companion.uniformDoubleNDFromRanges(
     vararg ranges: Pair<ClosedFloatingPointRange<Double>, Int>,
-): UniformHistogramGroupND<Double, DoubleField> =
-    uniformNDFromRanges(DoubleFieldOpsND, *ranges, bufferFactory = ::DoubleBuffer)
\ No newline at end of file
+): UniformHistogramGroupND<Double, Float64Field> = uniformNDFromRanges(Floa64FieldOpsND, *ranges)
\ No newline at end of file
diff --git a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt
index 54806c9fa..f6c80a903 100644
--- a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt
+++ b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/UniformHistogram1DTest.kt b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/UniformHistogram1DTest.kt
index fa129fad6..e90dae0fc 100644
--- a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/UniformHistogram1DTest.kt
+++ b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/UniformHistogram1DTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -9,7 +9,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runTest
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.distributions.NormalDistribution
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.random.RandomGenerator
 import space.kscience.kmath.stat.nextBuffer
 import kotlin.native.concurrent.ThreadLocal
@@ -22,7 +22,7 @@ internal class UniformHistogram1DTest {
     @Test
     fun normal() = runTest {
         val distribution = NormalDistribution(0.0, 1.0)
-        with(Histogram.uniform1D(DoubleField, 0.1)) {
+        with(Histogram.uniform1D(Float64Field, 0.1)) {
             val h1 = produce(distribution.nextBuffer(generator, 10000))
 
             val h2 = produce(distribution.nextBuffer(generator, 50000))
@@ -35,16 +35,16 @@ internal class UniformHistogram1DTest {
 
     @Test
     fun rebinDown() = runTest {
-        val h1 = Histogram.uniform1D(DoubleField, 0.01).produce(generator.nextDoubleBuffer(10000))
-        val h2 = Histogram.uniform1D(DoubleField, 0.03).produceFrom(h1)
+        val h1 = Histogram.uniform1D(Float64Field, 0.01).produce(generator.nextDoubleBuffer(10000))
+        val h2 = Histogram.uniform1D(Float64Field, 0.03).produceFrom(h1)
 
         assertEquals(10000, h2.bins.sumOf { it.binValue }.toInt())
     }
 
     @Test
     fun rebinUp() = runTest {
-        val h1 = Histogram.uniform1D(DoubleField, 0.03).produce(generator.nextDoubleBuffer(10000))
-        val h2 = Histogram.uniform1D(DoubleField, 0.01).produceFrom(h1)
+        val h1 = Histogram.uniform1D(Float64Field, 0.03).produce(generator.nextDoubleBuffer(10000))
+        val h2 = Histogram.uniform1D(Float64Field, 0.01).produceFrom(h1)
 
         assertEquals(10000, h2.bins.sumOf { it.binValue }.toInt())
     }
diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramGroup.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramGroup.kt
index 772db7df3..c8be4f846 100644
--- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramGroup.kt
+++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramGroup.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -14,10 +14,7 @@ import space.kscience.kmath.misc.sorted
 import space.kscience.kmath.operations.Group
 import space.kscience.kmath.operations.Ring
 import space.kscience.kmath.operations.ScaleOperations
-import space.kscience.kmath.structures.Buffer
-import space.kscience.kmath.structures.first
-import space.kscience.kmath.structures.indices
-import space.kscience.kmath.structures.last
+import space.kscience.kmath.structures.*
 import java.util.*
 
 private fun <B : ClosedRange<Double>> TreeMap<Double, B>.getBin(value: Double): B? {
@@ -53,6 +50,8 @@ public class TreeHistogramGroup<V : Any, A>(
     @PublishedApi internal val binFactory: (Double) -> DoubleDomain1D,
 ) : Group<TreeHistogram<V>>, ScaleOperations<TreeHistogram<V>> where A : Ring<V>, A : ScaleOperations<V> {
 
+    override val bufferFactory: MutableBufferFactory<TreeHistogram<V>> = MutableBufferFactory()
+
     internal inner class DomainCounter(val domain: DoubleDomain1D, val counter: Counter<V> = Counter.of(valueAlgebra)) :
         ClosedRange<Double> by domain.range
 
diff --git a/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt b/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt
index b7c1f34ba..3b605e9c1 100644
--- a/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt
+++ b/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,7 +7,7 @@ package space.kscience.kmath.histogram
 
 import org.junit.jupiter.api.Test
 import space.kscience.kmath.UnstableKMathAPI
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.real.step
 import kotlin.random.Random
 import kotlin.test.assertEquals
@@ -18,14 +18,14 @@ class TreeHistogramTest {
 
     @Test
     fun normalFill() {
-        val random  = Random(123)
-        val histogram = Histogram.custom1D(DoubleField, 0.0..1.0 step 0.1).produce {
+        val random = Random(123)
+        val histogram = Histogram.custom1D(Float64Field, 0.0..1.0 step 0.1).produce {
             repeat(100_000) {
                 putValue(random.nextDouble())
             }
         }
 
-        assertTrue { histogram.bins.count() > 8}
+        assertTrue { histogram.bins.count() > 8 }
         assertEquals(100_000, histogram.bins.sumOf { it.binValue }.toInt())
     }
 }
\ No newline at end of file
diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md
index 47142f174..2f8f365c1 100644
--- a/kmath-jafama/README.md
+++ b/kmath-jafama/README.md
@@ -7,19 +7,8 @@ Integration with [Jafama](https://github.com/jeffhain/jafama).
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-jafama:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-jafama:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-jafama:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -28,7 +17,7 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-jafama:0.4.0-dev-1")
+    implementation("space.kscience:kmath-jafama:0.4.0")
 }
 ```
 
@@ -50,6 +39,7 @@ fun main() {
 
 ## Performance
 
-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.
 
 > **Can't find appropriate benchmark data. Try generating readme files after running benchmarks**.
diff --git a/kmath-jafama/api/kmath-jafama.api b/kmath-jafama/api/kmath-jafama.api
new file mode 100644
index 000000000..989634e9b
--- /dev/null
+++ b/kmath-jafama/api/kmath-jafama.api
@@ -0,0 +1,128 @@
+public final class space/kscience/kmath/jafama/JafamaDoubleField : space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/ScaleOperations {
+	public static final field INSTANCE Lspace/kscience/kmath/jafama/JafamaDoubleField;
+	public fun acos (D)Ljava/lang/Double;
+	public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun acosh (D)Ljava/lang/Double;
+	public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun add (DD)Ljava/lang/Double;
+	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun asin (D)Ljava/lang/Double;
+	public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun asinh (D)Ljava/lang/Double;
+	public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun atan (D)Ljava/lang/Double;
+	public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun atanh (D)Ljava/lang/Double;
+	public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2;
+	public fun cos (D)Ljava/lang/Double;
+	public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun cosh (D)Ljava/lang/Double;
+	public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun div (DD)Ljava/lang/Double;
+	public synthetic fun div (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun divide (DD)Ljava/lang/Double;
+	public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun exp (D)Ljava/lang/Double;
+	public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
+	public fun getOne ()Ljava/lang/Double;
+	public synthetic fun getOne ()Ljava/lang/Object;
+	public fun getZero ()Ljava/lang/Double;
+	public synthetic fun getZero ()Ljava/lang/Object;
+	public fun ln (D)Ljava/lang/Double;
+	public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun minus (DD)Ljava/lang/Double;
+	public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun multiply (DD)Ljava/lang/Double;
+	public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun norm (D)Ljava/lang/Double;
+	public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun number (Ljava/lang/Number;)Ljava/lang/Double;
+	public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
+	public fun plus (DD)Ljava/lang/Double;
+	public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun power (DLjava/lang/Number;)Ljava/lang/Double;
+	public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
+	public fun scale (DD)Ljava/lang/Double;
+	public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object;
+	public fun sin (D)Ljava/lang/Double;
+	public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun sinh (D)Ljava/lang/Double;
+	public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun sqrt (D)Ljava/lang/Double;
+	public synthetic fun sqrt (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun tan (D)Ljava/lang/Double;
+	public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun tanh (D)Ljava/lang/Double;
+	public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun times (DD)Ljava/lang/Double;
+	public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun unaryMinus (D)Ljava/lang/Double;
+	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
+}
+
+public final class space/kscience/kmath/jafama/StrictJafamaDoubleField : space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/ScaleOperations {
+	public static final field INSTANCE Lspace/kscience/kmath/jafama/StrictJafamaDoubleField;
+	public fun acos (D)Ljava/lang/Double;
+	public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun acosh (D)Ljava/lang/Double;
+	public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun add (DD)Ljava/lang/Double;
+	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun asin (D)Ljava/lang/Double;
+	public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun asinh (D)Ljava/lang/Double;
+	public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun atan (D)Ljava/lang/Double;
+	public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun atanh (D)Ljava/lang/Double;
+	public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2;
+	public fun cos (D)Ljava/lang/Double;
+	public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun cosh (D)Ljava/lang/Double;
+	public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun div (DD)Ljava/lang/Double;
+	public synthetic fun div (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun divide (DD)Ljava/lang/Double;
+	public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun exp (D)Ljava/lang/Double;
+	public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun getBufferFactory ()Lspace/kscience/kmath/structures/MutableBufferFactory;
+	public fun getOne ()Ljava/lang/Double;
+	public synthetic fun getOne ()Ljava/lang/Object;
+	public fun getZero ()Ljava/lang/Double;
+	public synthetic fun getZero ()Ljava/lang/Object;
+	public fun ln (D)Ljava/lang/Double;
+	public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun minus (DD)Ljava/lang/Double;
+	public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun multiply (DD)Ljava/lang/Double;
+	public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun norm (D)Ljava/lang/Double;
+	public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun number (Ljava/lang/Number;)Ljava/lang/Double;
+	public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
+	public fun plus (DD)Ljava/lang/Double;
+	public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun power (DLjava/lang/Number;)Ljava/lang/Double;
+	public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
+	public fun scale (DD)Ljava/lang/Double;
+	public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object;
+	public fun sin (D)Ljava/lang/Double;
+	public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun sinh (D)Ljava/lang/Double;
+	public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun sqrt (D)Ljava/lang/Double;
+	public synthetic fun sqrt (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun tan (D)Ljava/lang/Double;
+	public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun tanh (D)Ljava/lang/Double;
+	public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun times (DD)Ljava/lang/Double;
+	public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun unaryMinus (D)Ljava/lang/Double;
+	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
+}
+
diff --git a/kmath-jafama/build.gradle.kts b/kmath-jafama/build.gradle.kts
index 5a77a97ed..0390224ba 100644
--- a/kmath-jafama/build.gradle.kts
+++ b/kmath-jafama/build.gradle.kts
@@ -14,7 +14,7 @@ repositories {
 }
 
 readme {
-    maturity = space.kscience.gradle.Maturity.PROTOTYPE
+    maturity = space.kscience.gradle.Maturity.DEPRECATED
     propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
 
     feature("jafama-double", "src/main/kotlin/space/kscience/kmath/jafama/") {
diff --git a/kmath-jafama/docs/README-TEMPLATE.md b/kmath-jafama/docs/README-TEMPLATE.md
index 54348467b..2973fca3b 100644
--- a/kmath-jafama/docs/README-TEMPLATE.md
+++ b/kmath-jafama/docs/README-TEMPLATE.md
@@ -24,6 +24,7 @@ fun main() {
 
 ## Performance
 
-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.
 
 ${benchmarkJafamaDouble}
diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt
index f9b8287b4..1b7bbf3ed 100644
--- a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt
+++ b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,16 +7,17 @@ package space.kscience.kmath.jafama
 
 import net.jafama.FastMath
 import net.jafama.StrictFastMath
-import space.kscience.kmath.operations.ExtendedField
-import space.kscience.kmath.operations.Norm
-import space.kscience.kmath.operations.PowerOperations
-import space.kscience.kmath.operations.ScaleOperations
+import space.kscience.kmath.operations.*
+import space.kscience.kmath.structures.MutableBufferFactory
 
 /**
  * A field for [Double] (using FastMath) without boxing. Does not produce appropriate field element.
  */
 @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
 public object JafamaDoubleField : ExtendedField<Double>, Norm<Double, Double>, ScaleOperations<Double> {
+
+    override val bufferFactory: MutableBufferFactory<Double> get() = DoubleField.bufferFactory
+
     override inline val zero: Double get() = 0.0
     override inline val one: Double get() = 1.0
 
@@ -68,6 +69,9 @@ public object JafamaDoubleField : ExtendedField<Double>, Norm<Double, Double>, S
  */
 @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
 public object StrictJafamaDoubleField : ExtendedField<Double>, Norm<Double, Double>, ScaleOperations<Double> {
+
+    override val bufferFactory: MutableBufferFactory<Double> get() = DoubleField.bufferFactory
+
     override inline val zero: Double get() = 0.0
     override inline val one: Double get() = 1.0
 
diff --git a/kmath-jupyter/README.md b/kmath-jupyter/README.md
index 2b26878dc..8a425dff0 100644
--- a/kmath-jupyter/README.md
+++ b/kmath-jupyter/README.md
@@ -6,19 +6,8 @@
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-jupyter:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-jupyter:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-jupyter:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -27,6 +16,6 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-jupyter:0.4.0-dev-1")
+    implementation("space.kscience:kmath-jupyter:0.4.0")
 }
 ```
diff --git a/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt b/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt
index 944666c9e..36ce25c03 100644
--- a/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt
+++ b/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-kotlingrad/README.md b/kmath-kotlingrad/README.md
index f1a918b4b..697662245 100644
--- a/kmath-kotlingrad/README.md
+++ b/kmath-kotlingrad/README.md
@@ -8,19 +8,8 @@
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-kotlingrad:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -29,6 +18,6 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-kotlingrad:0.4.0-dev-1")
+    implementation("space.kscience:kmath-kotlingrad:0.4.0")
 }
 ```
diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt
index cd35e0c42..c261e6f91 100644
--- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt
+++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt
index 110572140..07b77683d 100644
--- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt
+++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,6 +7,7 @@ package space.kscience.kmath.kotlingrad
 
 import ai.hypergraph.kotlingrad.api.SFun
 import ai.hypergraph.kotlingrad.api.SVar
+import space.kscience.attributes.SafeType
 import space.kscience.kmath.expressions.*
 import space.kscience.kmath.operations.NumericAlgebra
 
@@ -25,6 +26,8 @@ public class KotlingradExpression<T : Number, A : NumericAlgebra<T>>(
     public val algebra: A,
     public val mst: MST,
 ) : SpecialDifferentiableExpression<T, KotlingradExpression<T, A>> {
+    override val type: SafeType<T> = algebra.type
+
     override fun invoke(arguments: Map<Symbol, T>): T = mst.interpret(algebra, arguments)
 
     override fun derivativeOrNull(
diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt
index dd75a704c..363a698c6 100644
--- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt
+++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt b/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt
index ccd89f063..f536e103d 100644
--- a/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt
+++ b/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -12,7 +12,7 @@ import space.kscience.kmath.ast.parseMath
 import space.kscience.kmath.expressions.MstNumericAlgebra
 import space.kscience.kmath.expressions.Symbol.Companion.x
 import space.kscience.kmath.expressions.invoke
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import kotlin.test.Test
 import kotlin.test.assertEquals
 import kotlin.test.assertTrue
@@ -22,8 +22,8 @@ import kotlin.test.fail
 internal class AdaptingTests {
     @Test
     fun symbol() {
-        assertEquals(x.identity, x.toSVar<KMathNumber<Double, DoubleField>>().name)
-        val c2 = "kitten".parseMath().toSFun<KMathNumber<Double, DoubleField>>()
+        assertEquals(x.identity, x.toSVar<KMathNumber<Double, Float64Field>>().name)
+        val c2 = "kitten".parseMath().toSFun<KMathNumber<Double, Float64Field>>()
         if (c2 is SVar<*>) assertTrue(c2.name == "kitten") else fail()
     }
 
@@ -31,15 +31,15 @@ internal class AdaptingTests {
     fun number() {
         val c1 = MstNumericAlgebra.number(12354324)
         assertTrue(c1.toSConst<DReal>().doubleValue == 12354324.0)
-        val c2 = "0.234".parseMath().toSFun<KMathNumber<Double, DoubleField>>()
+        val c2 = "0.234".parseMath().toSFun<KMathNumber<Double, Float64Field>>()
         if (c2 is SConst<*>) assertTrue(c2.doubleValue == 0.234) else fail()
-        val c3 = "1e-3".parseMath().toSFun<KMathNumber<Double, DoubleField>>()
+        val c3 = "1e-3".parseMath().toSFun<KMathNumber<Double, Float64Field>>()
         if (c3 is SConst<*>) assertEquals(0.001, c3.value) else fail()
     }
 
     @Test
     fun simpleFunctionShape() {
-        val linear = "2*x+16".parseMath().toSFun<KMathNumber<Double, DoubleField>>()
+        val linear = "2*x+16".parseMath().toSFun<KMathNumber<Double, Float64Field>>()
         if (linear !is Sum<*>) fail()
         if (linear.left !is Prod<*>) fail()
         if (linear.right !is SConst<*>) fail()
@@ -47,22 +47,22 @@ internal class AdaptingTests {
 
     @Test
     fun simpleFunctionDerivative() {
-        val xSVar = x.toSVar<KMathNumber<Double, DoubleField>>()
-        val quadratic = "x^2-4*x-44".parseMath().toSFun<KMathNumber<Double, DoubleField>>()
-        val actualDerivative = quadratic.d(xSVar).toMst().compileToExpression(DoubleField)
-        val expectedDerivative = "2*x-4".parseMath().compileToExpression(DoubleField)
+        val xSVar = x.toSVar<KMathNumber<Double, Float64Field>>()
+        val quadratic = "x^2-4*x-44".parseMath().toSFun<KMathNumber<Double, Float64Field>>()
+        val actualDerivative = quadratic.d(xSVar).toMst().compileToExpression(Float64Field)
+        val expectedDerivative = "2*x-4".parseMath().compileToExpression(Float64Field)
         assertEquals(actualDerivative(x to 123.0), expectedDerivative(x to 123.0))
     }
 
     @Test
     fun moreComplexDerivative() {
-        val xSVar = x.toSVar<KMathNumber<Double, DoubleField>>()
-        val composition = "-sqrt(sin(x^2)-cos(x)^2-16*x)".parseMath().toSFun<KMathNumber<Double, DoubleField>>()
-        val actualDerivative = composition.d(xSVar).toMst().compileToExpression(DoubleField)
+        val xSVar = x.toSVar<KMathNumber<Double, Float64Field>>()
+        val composition = "-sqrt(sin(x^2)-cos(x)^2-16*x)".parseMath().toSFun<KMathNumber<Double, Float64Field>>()
+        val actualDerivative = composition.d(xSVar).toMst().compileToExpression(Float64Field)
 
         val expectedDerivative = "-(2*x*cos(x^2)+2*sin(x)*cos(x)-16)/(2*sqrt(sin(x^2)-16*x-cos(x)^2))"
             .parseMath()
-            .compileToExpression(DoubleField)
+            .compileToExpression(Float64Field)
 
         assertEquals(actualDerivative(x to -0.1), expectedDerivative(x to -0.1))
     }
diff --git a/kmath-memory/README.md b/kmath-memory/README.md
index 594588ecf..5f08023b0 100644
--- a/kmath-memory/README.md
+++ b/kmath-memory/README.md
@@ -6,19 +6,8 @@
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-memory:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-memory:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-memory:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -27,6 +16,6 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-memory:0.4.0-dev-1")
+    implementation("space.kscience:kmath-memory:0.4.0")
 }
 ```
diff --git a/kmath-memory/api/kmath-memory.api b/kmath-memory/api/kmath-memory.api
index cebb04af2..d8bfe6625 100644
--- a/kmath-memory/api/kmath-memory.api
+++ b/kmath-memory/api/kmath-memory.api
@@ -1,14 +1,3 @@
-public abstract interface annotation class space/kscience/kmath/PerformancePitfall : java/lang/annotation/Annotation {
-	public abstract fun message ()Ljava/lang/String;
-}
-
-public abstract interface annotation class space/kscience/kmath/UnsafeKMathAPI : java/lang/annotation/Annotation {
-	public abstract fun message ()Ljava/lang/String;
-}
-
-public abstract interface annotation class space/kscience/kmath/UnstableKMathAPI : java/lang/annotation/Annotation {
-}
-
 public final class space/kscience/kmath/memory/ByteBufferMemory : space/kscience/kmath/memory/Memory {
 	public fun <init> (Ljava/nio/ByteBuffer;II)V
 	public synthetic fun <init> (Ljava/nio/ByteBuffer;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V
@@ -42,6 +31,22 @@ public abstract interface class space/kscience/kmath/memory/Memory {
 public final class space/kscience/kmath/memory/Memory$Companion {
 }
 
+public class space/kscience/kmath/memory/MemoryBuffer : space/kscience/kmath/structures/Buffer {
+	public static final field Companion Lspace/kscience/kmath/memory/MemoryBuffer$Companion;
+	public fun <init> (Lspace/kscience/kmath/memory/Memory;Lspace/kscience/kmath/memory/MemorySpec;)V
+	public fun get (I)Ljava/lang/Object;
+	protected final fun getMemory ()Lspace/kscience/kmath/memory/Memory;
+	public fun getSize ()I
+	protected final fun getSpec ()Lspace/kscience/kmath/memory/MemorySpec;
+	public fun iterator ()Ljava/util/Iterator;
+	public fun toString ()Ljava/lang/String;
+}
+
+public final class space/kscience/kmath/memory/MemoryBuffer$Companion {
+	public final fun create (Lspace/kscience/kmath/memory/MemorySpec;I)Lspace/kscience/kmath/memory/MemoryBuffer;
+	public final fun create (Lspace/kscience/kmath/memory/MemorySpec;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/memory/MemoryBuffer;
+}
+
 public final class space/kscience/kmath/memory/MemoryKt {
 	public static final fun read (Lspace/kscience/kmath/memory/Memory;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
 	public static final fun write (Lspace/kscience/kmath/memory/Memory;Lkotlin/jvm/functions/Function1;)V
@@ -58,7 +63,7 @@ public abstract interface class space/kscience/kmath/memory/MemoryReader : java/
 	public abstract fun readShort (I)S
 }
 
-public abstract interface class space/kscience/kmath/memory/MemorySpec {
+public abstract interface class space/kscience/kmath/memory/MemorySpec : space/kscience/attributes/WithType {
 	public abstract fun getObjectSize ()I
 	public abstract fun read (Lspace/kscience/kmath/memory/MemoryReader;I)Ljava/lang/Object;
 	public abstract fun write (Lspace/kscience/kmath/memory/MemoryWriter;ILjava/lang/Object;)V
@@ -81,3 +86,14 @@ public abstract interface class space/kscience/kmath/memory/MemoryWriter : java/
 	public abstract fun writeShort (IS)V
 }
 
+public final class space/kscience/kmath/memory/MutableMemoryBuffer : space/kscience/kmath/memory/MemoryBuffer, space/kscience/kmath/structures/MutableBuffer {
+	public static final field Companion Lspace/kscience/kmath/memory/MutableMemoryBuffer$Companion;
+	public fun <init> (Lspace/kscience/kmath/memory/Memory;Lspace/kscience/kmath/memory/MemorySpec;)V
+	public fun set (ILjava/lang/Object;)V
+}
+
+public final class space/kscience/kmath/memory/MutableMemoryBuffer$Companion {
+	public final fun create (Lspace/kscience/kmath/memory/MemorySpec;I)Lspace/kscience/kmath/memory/MutableMemoryBuffer;
+	public final fun create (Lspace/kscience/kmath/memory/MemorySpec;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/memory/MutableMemoryBuffer;
+}
+
diff --git a/kmath-memory/build.gradle.kts b/kmath-memory/build.gradle.kts
index 8c1e63cb7..d2e50b10b 100644
--- a/kmath-memory/build.gradle.kts
+++ b/kmath-memory/build.gradle.kts
@@ -6,21 +6,10 @@ kscience {
     jvm()
     js()
     native()
-    wasm{
-        browser {
-            testTask {
-                useKarma {
-                    webpackConfig.experiments.add("topLevelAwait")
-                    useChromeHeadless()
-                }
-            }
-        }
-    }
+    wasm()
 
-    wasmTest{
-        dependencies {
-            implementation(kotlin("test"))
-        }
+    dependencies {
+        api(projects.kmathCore)
     }
 }
 
@@ -30,3 +19,6 @@ readme {
         An API and basic implementation for arranging objects in a continuous memory block.
     """.trimIndent()
 }
+
+//rootProject.the<NodeJsRootExtension>().versions.webpack.version = "5.76.2"
+//rootProject.the<NodeJsRootExtension>().nodeVersion = "20.8.0"
diff --git a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt
index a63753015..7b5e0438e 100644
--- a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt
+++ b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -43,7 +43,7 @@ public interface Memory {
 /**
  * The interface to read primitive types in this memory.
  */
-public interface MemoryReader: AutoCloseable {
+public interface MemoryReader : AutoCloseable {
     /**
      * The underlying memory.
      */
@@ -96,7 +96,7 @@ public inline fun <R> Memory.read(block: MemoryReader.() -> R): R {
 /**
  * The interface to write primitive types into this memory.
  */
-public interface MemoryWriter: AutoCloseable {
+public interface MemoryWriter : AutoCloseable {
     /**
      * The underlying memory.
      */
diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MemoryBuffer.kt b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemoryBuffer.kt
similarity index 86%
rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MemoryBuffer.kt
rename to kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemoryBuffer.kt
index cbfd6b9cd..27deea126 100644
--- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MemoryBuffer.kt
+++ b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemoryBuffer.kt
@@ -1,11 +1,12 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
-package space.kscience.kmath.structures
+package space.kscience.kmath.memory
 
-import space.kscience.kmath.memory.*
+import space.kscience.kmath.structures.Buffer
+import space.kscience.kmath.structures.MutableBuffer
 
 /**
  * A non-boxing buffer over [Memory] object.
@@ -15,6 +16,7 @@ import space.kscience.kmath.memory.*
  * @property spec the spec of [T] type.
  */
 public open class MemoryBuffer<T : Any>(protected val memory: Memory, protected val spec: MemorySpec<T>) : Buffer<T> {
+
     override val size: Int get() = memory.size / spec.objectSize
 
     override operator fun get(index: Int): T = memory.read { read(spec, spec.objectSize * index) }
@@ -43,13 +45,14 @@ public open class MemoryBuffer<T : Any>(protected val memory: Memory, protected
  * @property memory the underlying memory segment.
  * @property spec the spec of [T] type.
  */
-public class MutableMemoryBuffer<T : Any>(memory: Memory, spec: MemorySpec<T>) : MemoryBuffer<T>(memory, spec),
-    MutableBuffer<T> {
+public class MutableMemoryBuffer<T : Any>(
+    memory: Memory,
+    spec: MemorySpec<T>,
+) : MemoryBuffer<T>(memory, spec), MutableBuffer<T> {
 
     private val writer: MemoryWriter = memory.writer()
 
     override operator fun set(index: Int, value: T): Unit = writer.write(spec, spec.objectSize * index, value)
-    override fun copy(): MutableBuffer<T> = MutableMemoryBuffer(memory.copy(), spec)
 
     public companion object {
         public fun <T : Any> create(spec: MemorySpec<T>, size: Int): MutableMemoryBuffer<T> =
diff --git a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt
index 19bc3bae4..1a8c2d74a 100644
--- a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt
+++ b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt
@@ -1,16 +1,19 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.memory
 
+import space.kscience.attributes.WithType
+
 /**
  * A specification to read or write custom objects with fixed size in bytes.
  *
  * @param T the type of object this spec manages.
  */
-public interface MemorySpec<T : Any> {
+public interface MemorySpec<T : Any> : WithType<T> {
+
     /**
      * Size of [T] in bytes after serialization.
      */
diff --git a/kmath-memory/src/commonTest/kotlin/space/kscience/kmath/memory/MemoryTest.kt b/kmath-memory/src/commonTest/kotlin/space/kscience/kmath/memory/MemoryTest.kt
index 3726ddbb7..57003201d 100644
--- a/kmath-memory/src/commonTest/kotlin/space/kscience/kmath/memory/MemoryTest.kt
+++ b/kmath-memory/src/commonTest/kotlin/space/kscience/kmath/memory/MemoryTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2023 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -20,18 +20,18 @@ class MemoryTest {
         val memory = Memory.allocate(memorySize)
         memory.write {
             for (i in 0 until (memory.size / 4)) {
-                writeInt(i*4, data[i])
+                writeInt(i * 4, data[i])
             }
         }
 
         val result = memory.read {
             buildList {
                 for (i in 0 until (memory.size / 4)) {
-                    add(readInt(i*4))
+                    add(readInt(i * 4))
                 }
             }
         }
 
-        assertEquals(data,result)
+        assertEquals(data, result)
     }
 }
\ No newline at end of file
diff --git a/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt b/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt
index f8bcef010..f7badde37 100644
--- a/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt
+++ b/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt b/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt
index d022cab23..c240e512d 100644
--- a/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt
+++ b/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt b/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt
index 32bc8d6a5..5edad57c4 100644
--- a/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt
+++ b/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt
@@ -1,10 +1,12 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.memory
 
+import kotlin.experimental.ExperimentalNativeApi
+
 @PublishedApi
 internal class NativeMemory(
     val array: ByteArray,
@@ -26,6 +28,7 @@ internal class NativeMemory(
         return NativeMemory(copy)
     }
 
+    @OptIn(ExperimentalNativeApi::class)
     private val reader: MemoryReader = object : MemoryReader {
         override val memory: Memory get() = this@NativeMemory
 
@@ -48,6 +51,7 @@ internal class NativeMemory(
 
     override fun reader(): MemoryReader = reader
 
+    @OptIn(ExperimentalNativeApi::class)
     private val writer: MemoryWriter = object : MemoryWriter {
         override val memory: Memory get() = this@NativeMemory
 
diff --git a/kmath-memory/src/wasmMain/kotlin/space/kscience/kmath/memory/WasmDataViewMemory.kt b/kmath-memory/src/wasmJsMain/kotlin/space/kscience/kmath/memory/WasmDataViewMemory.kt
similarity index 98%
rename from kmath-memory/src/wasmMain/kotlin/space/kscience/kmath/memory/WasmDataViewMemory.kt
rename to kmath-memory/src/wasmJsMain/kotlin/space/kscience/kmath/memory/WasmDataViewMemory.kt
index 0cff551fa..30172b8b1 100644
--- a/kmath-memory/src/wasmMain/kotlin/space/kscience/kmath/memory/WasmDataViewMemory.kt
+++ b/kmath-memory/src/wasmJsMain/kotlin/space/kscience/kmath/memory/WasmDataViewMemory.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-multik/README.md b/kmath-multik/README.md
index 127b12a49..f69d5d5d0 100644
--- a/kmath-multik/README.md
+++ b/kmath-multik/README.md
@@ -6,19 +6,8 @@ JetBrains Multik connector
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-multik:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-multik:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-multik:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -27,6 +16,6 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-multik:0.4.0-dev-1")
+    implementation("space.kscience:kmath-multik:0.4.0")
 }
 ```
diff --git a/kmath-multik/build.gradle.kts b/kmath-multik/build.gradle.kts
index fc51d2c21..e3f27effe 100644
--- a/kmath-multik/build.gradle.kts
+++ b/kmath-multik/build.gradle.kts
@@ -11,16 +11,16 @@ kscience {
     js()
 }
 
-kotlin{
-    sourceSets{
-        commonMain{
-            dependencies{
-                api(project(":kmath-tensors"))
+kotlin {
+    sourceSets {
+        commonMain {
+            dependencies {
+                api(projects.kmathTensors)
                 api("org.jetbrains.kotlinx:multik-core:$multikVersion")
             }
         }
-        commonTest{
-            dependencies{
+        commonTest {
+            dependencies {
                 api("org.jetbrains.kotlinx:multik-default:$multikVersion")
             }
         }
diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt
index beab5c18b..6a8749946 100644
--- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt
+++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -11,25 +11,27 @@ import org.jetbrains.kotlinx.multik.api.ndarrayOf
 import org.jetbrains.kotlinx.multik.ndarray.data.DataType
 import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.nd.StructureND
-import space.kscience.kmath.operations.DoubleField
 import space.kscience.kmath.operations.ExponentialOperations
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.TrigonometricOperations
 
 public class MultikDoubleAlgebra(
-    multikEngine: Engine
-) : MultikDivisionTensorAlgebra<Double, DoubleField>(multikEngine),
+    multikEngine: Engine,
+) : MultikDivisionTensorAlgebra<Double, Float64Field>(multikEngine),
     TrigonometricOperations<StructureND<Double>>, ExponentialOperations<StructureND<Double>> {
-    override val elementAlgebra: DoubleField get() = DoubleField
-    override val type: DataType get() = DataType.DoubleDataType
+    override val elementAlgebra: Float64Field get() = Float64Field
+    override val dataType: DataType get() = DataType.DoubleDataType
 
-    override fun sin(arg: StructureND<Double>): MultikTensor<Double> = multikMath.mathEx.sin(arg.asMultik().array).wrap()
+    override fun sin(arg: StructureND<Double>): MultikTensor<Double> =
+        multikMath.mathEx.sin(arg.asMultik().array).wrap()
 
-    override fun cos(arg: StructureND<Double>): MultikTensor<Double> = multikMath.mathEx.cos(arg.asMultik().array).wrap()
+    override fun cos(arg: StructureND<Double>): MultikTensor<Double> =
+        multikMath.mathEx.cos(arg.asMultik().array).wrap()
 
     override fun tan(arg: StructureND<Double>): MultikTensor<Double> = sin(arg) / cos(arg)
 
     @PerformancePitfall
-    override fun asin(arg: StructureND<Double>): MultikTensor<Double>  = arg.map { asin(it) }
+    override fun asin(arg: StructureND<Double>): MultikTensor<Double> = arg.map { asin(it) }
 
     @PerformancePitfall
     override fun acos(arg: StructureND<Double>): MultikTensor<Double> = arg.map { acos(it) }
@@ -37,7 +39,8 @@ public class MultikDoubleAlgebra(
     @PerformancePitfall
     override fun atan(arg: StructureND<Double>): MultikTensor<Double> = arg.map { atan(it) }
 
-    override fun exp(arg: StructureND<Double>): MultikTensor<Double> = multikMath.mathEx.exp(arg.asMultik().array).wrap()
+    override fun exp(arg: StructureND<Double>): MultikTensor<Double> =
+        multikMath.mathEx.exp(arg.asMultik().array).wrap()
 
     override fun ln(arg: StructureND<Double>): MultikTensor<Double> = multikMath.mathEx.log(arg.asMultik().array).wrap()
 
@@ -60,7 +63,7 @@ public class MultikDoubleAlgebra(
     @PerformancePitfall
     override fun atanh(arg: StructureND<Double>): MultikTensor<Double> = arg.map { atanh(it) }
 
-    override fun scalar(value: Double): MultikTensor<Double>  = Multik.ndarrayOf(value).wrap()
+    override fun scalar(value: Double): MultikTensor<Double> = Multik.ndarrayOf(value).wrap()
 }
 
 //public val Double.Companion.multikAlgebra: MultikTensorAlgebra<Double, DoubleField> get() = MultikDoubleAlgebra
diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt
index ee194ae24..54a60e38a 100644
--- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt
+++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -9,13 +9,13 @@ import org.jetbrains.kotlinx.multik.api.Engine
 import org.jetbrains.kotlinx.multik.api.Multik
 import org.jetbrains.kotlinx.multik.api.ndarrayOf
 import org.jetbrains.kotlinx.multik.ndarray.data.DataType
-import space.kscience.kmath.operations.FloatField
+import space.kscience.kmath.operations.Float32Field
 
 public class MultikFloatAlgebra(
-    multikEngine: Engine
-) : MultikDivisionTensorAlgebra<Float, FloatField>(multikEngine) {
-    override val elementAlgebra: FloatField get() = FloatField
-    override val type: DataType get() = DataType.FloatDataType
+    multikEngine: Engine,
+) : MultikDivisionTensorAlgebra<Float, Float32Field>(multikEngine) {
+    override val elementAlgebra: Float32Field get() = Float32Field
+    override val dataType: DataType get() = DataType.FloatDataType
 
     override fun scalar(value: Float): MultikTensor<Float> = Multik.ndarrayOf(value).wrap()
 }
diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt
index 05b240787..c6cbae554 100644
--- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt
+++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -9,14 +9,14 @@ import org.jetbrains.kotlinx.multik.api.Engine
 import org.jetbrains.kotlinx.multik.api.Multik
 import org.jetbrains.kotlinx.multik.api.ndarrayOf
 import org.jetbrains.kotlinx.multik.ndarray.data.DataType
-import space.kscience.kmath.operations.IntRing
+import space.kscience.kmath.operations.Int32Ring
 
 public class MultikIntAlgebra(
-    multikEngine: Engine
-) : MultikTensorAlgebra<Int, IntRing>(multikEngine) {
-    override val elementAlgebra: IntRing get() = IntRing
-    override val type: DataType get() = DataType.IntDataType
-    override fun scalar(value: Int): MultikTensor<Int>  = Multik.ndarrayOf(value).wrap()
+    multikEngine: Engine,
+) : MultikTensorAlgebra<Int, Int32Ring>(multikEngine) {
+    override val elementAlgebra: Int32Ring get() = Int32Ring
+    override val dataType: DataType get() = DataType.IntDataType
+    override fun scalar(value: Int): MultikTensor<Int> = Multik.ndarrayOf(value).wrap()
 }
 
 //public val Int.Companion.multikAlgebra: MultikTensorAlgebra<Int, IntRing> get() = MultikIntAlgebra
diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt
index e713e556e..b30eaa580 100644
--- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt
+++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -9,15 +9,15 @@ import org.jetbrains.kotlinx.multik.api.Engine
 import org.jetbrains.kotlinx.multik.api.Multik
 import org.jetbrains.kotlinx.multik.api.ndarrayOf
 import org.jetbrains.kotlinx.multik.ndarray.data.DataType
-import space.kscience.kmath.operations.LongRing
+import space.kscience.kmath.operations.Int64Ring
 
 public class MultikLongAlgebra(
-    multikEngine: Engine
-) : MultikTensorAlgebra<Long, LongRing>(multikEngine) {
-    override val elementAlgebra: LongRing get() = LongRing
-    override val type: DataType get() = DataType.LongDataType
+    multikEngine: Engine,
+) : MultikTensorAlgebra<Long, Int64Ring>(multikEngine) {
+    override val elementAlgebra: Int64Ring get() = Int64Ring
+    override val dataType: DataType get() = DataType.LongDataType
 
-    override fun scalar(value: Long): MultikTensor<Long>  = Multik.ndarrayOf(value).wrap()
+    override fun scalar(value: Long): MultikTensor<Long> = Multik.ndarrayOf(value).wrap()
 }
 
 
diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt
index 6e5ca5882..9403e8d6d 100644
--- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt
+++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -9,14 +9,14 @@ import org.jetbrains.kotlinx.multik.api.Engine
 import org.jetbrains.kotlinx.multik.api.Multik
 import org.jetbrains.kotlinx.multik.api.ndarrayOf
 import org.jetbrains.kotlinx.multik.ndarray.data.DataType
-import space.kscience.kmath.operations.ShortRing
+import space.kscience.kmath.operations.Int16Ring
 
 public class MultikShortAlgebra(
-    multikEngine: Engine
-) : MultikTensorAlgebra<Short, ShortRing>(multikEngine) {
-    override val elementAlgebra: ShortRing get() = ShortRing
-    override val type: DataType get() = DataType.ShortDataType
-    override fun scalar(value: Short): MultikTensor<Short>  = Multik.ndarrayOf(value).wrap()
+    multikEngine: Engine,
+) : MultikTensorAlgebra<Short, Int16Ring>(multikEngine) {
+    override val elementAlgebra: Int16Ring get() = Int16Ring
+    override val dataType: DataType get() = DataType.ShortDataType
+    override fun scalar(value: Short): MultikTensor<Short> = Multik.ndarrayOf(value).wrap()
 }
 
 //public val Short.Companion.multikAlgebra: MultikTensorAlgebra<Short, ShortRing> get() = MultikShortAlgebra
diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensor.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensor.kt
index 59a9a1bf3..20916d934 100644
--- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensor.kt
+++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensor.kt
@@ -1,18 +1,35 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.multik
 
 import org.jetbrains.kotlinx.multik.ndarray.data.*
+import space.kscience.attributes.SafeType
+import space.kscience.attributes.safeTypeOf
 import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.nd.ShapeND
+import space.kscience.kmath.operations.*
 import space.kscience.kmath.tensors.api.Tensor
 import kotlin.jvm.JvmInline
 
+public val DataType.type: SafeType<*>
+    get() = when (this) {
+        DataType.ByteDataType -> ByteRing.type
+        DataType.ShortDataType -> ShortRing.type
+        DataType.IntDataType -> IntRing.type
+        DataType.LongDataType -> LongRing.type
+        DataType.FloatDataType -> Float32Field.type
+        DataType.DoubleDataType -> Float64Field.type
+        DataType.ComplexFloatDataType -> safeTypeOf<Pair<Float, Float>>()
+        DataType.ComplexDoubleDataType -> safeTypeOf<Pair<Double, Double>>()
+    }
+
+
 @JvmInline
 public value class MultikTensor<T>(public val array: MutableMultiArray<T, DN>) : Tensor<T> {
+
     override val shape: ShapeND get() = ShapeND(array.shape)
 
     @PerformancePitfall
diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt
index c3a82b167..c0209338c 100644
--- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt
+++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -26,16 +26,16 @@ public abstract class MultikTensorAlgebra<T, A : Ring<T>>(
     private val multikEngine: Engine,
 ) : TensorAlgebra<T, A> where T : Number, T : Comparable<T> {
 
-    public abstract val type: DataType
+    public abstract val dataType: DataType
 
     protected val multikMath: Math = multikEngine.getMath()
     protected val multikLinAl: LinAlg = multikEngine.getLinAlg()
     protected val multikStat: Statistics = multikEngine.getStatistics()
 
     @OptIn(UnsafeKMathAPI::class)
-    override fun structureND(shape: ShapeND, initializer: A.(IntArray) -> T): MultikTensor<T> {
+    override fun mutableStructureND(shape: ShapeND, initializer: A.(IntArray) -> T): MultikTensor<T> {
         val strides = ColumnStrides(shape)
-        val memoryView = initMemoryView<T>(strides.linearSize, type)
+        val memoryView = initMemoryView<T>(strides.linearSize, dataType)
         strides.asSequence().forEachIndexed { linearIndex, tensorIndex ->
             memoryView[linearIndex] = elementAlgebra.initializer(tensorIndex)
         }
@@ -44,12 +44,12 @@ public abstract class MultikTensorAlgebra<T, A : Ring<T>>(
 
     @OptIn(PerformancePitfall::class, UnsafeKMathAPI::class)
     override fun StructureND<T>.map(transform: A.(T) -> T): MultikTensor<T> = if (this is MultikTensor) {
-        val data = initMemoryView<T>(array.size, type)
+        val data = initMemoryView<T>(array.size, dataType)
         var count = 0
         for (el in array) data[count++] = elementAlgebra.transform(el)
         NDArray(data, shape = shape.asArray(), dim = array.dim).wrap()
     } else {
-        structureND(shape) { index ->
+        mutableStructureND(shape) { index ->
             transform(get(index))
         }
     }
@@ -58,7 +58,7 @@ public abstract class MultikTensorAlgebra<T, A : Ring<T>>(
     override fun StructureND<T>.mapIndexed(transform: A.(index: IntArray, T) -> T): MultikTensor<T> =
         if (this is MultikTensor) {
             val array = asMultik().array
-            val data = initMemoryView<T>(array.size, type)
+            val data = initMemoryView<T>(array.size, dataType)
             val indexIter = array.multiIndices.iterator()
             var index = 0
             for (item in array) {
@@ -70,7 +70,7 @@ public abstract class MultikTensorAlgebra<T, A : Ring<T>>(
             }
             NDArray(data, shape = array.shape, dim = array.dim).wrap()
         } else {
-            structureND(shape) { index ->
+            mutableStructureND(shape) { index ->
                 transform(index, get(index))
             }
         }
@@ -95,7 +95,7 @@ public abstract class MultikTensorAlgebra<T, A : Ring<T>>(
         require(left.shape.contentEquals(right.shape)) { "ND array shape mismatch" } //TODO replace by ShapeMismatchException
         val leftArray = left.asMultik().array
         val rightArray = right.asMultik().array
-        val data = initMemoryView<T>(leftArray.size, type)
+        val data = initMemoryView<T>(leftArray.size, dataType)
         var counter = 0
         val leftIterator = leftArray.iterator()
         val rightIterator = rightArray.iterator()
@@ -114,7 +114,7 @@ public abstract class MultikTensorAlgebra<T, A : Ring<T>>(
     public fun StructureND<T>.asMultik(): MultikTensor<T> = if (this is MultikTensor) {
         this
     } else {
-        val res = mk.zeros<T, DN>(shape.asArray(), type).asDNArray()
+        val res = mk.zeros<T, DN>(shape.asArray(), dataType).asDNArray()
         for (index in res.multiIndices) {
             res[index] = this[index]
         }
@@ -251,7 +251,12 @@ public abstract class MultikTensorAlgebra<T, A : Ring<T>>(
             TODO("Not implemented for broadcasting")
         }
 
-    override fun diagonalEmbedding(diagonalEntries: StructureND<T>, offset: Int, dim1: Int, dim2: Int): MultikTensor<T> {
+    override fun diagonalEmbedding(
+        diagonalEntries: StructureND<T>,
+        offset: Int,
+        dim1: Int,
+        dim2: Int,
+    ): MultikTensor<T> {
 
         TODO("Diagonal embedding not implemented")
     }
@@ -296,7 +301,7 @@ public abstract class MultikDivisionTensorAlgebra<T, A : Field<T>>(
 
     @OptIn(UnsafeKMathAPI::class)
     override fun T.div(arg: StructureND<T>): MultikTensor<T> =
-        Multik.ones<T, DN>(arg.shape.asArray(), type).apply { divAssign(arg.asMultik().array) }.wrap()
+        Multik.ones<T, DN>(arg.shape.asArray(), dataType).apply { divAssign(arg.asMultik().array) }.wrap()
 
     override fun StructureND<T>.div(arg: T): MultikTensor<T> =
         asMultik().array.div(arg).wrap()
diff --git a/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt b/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt
index 1a130aa92..fff88c70b 100644
--- a/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt
+++ b/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -10,7 +10,7 @@ import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.nd.ShapeND
 import space.kscience.kmath.nd.StructureND
 import space.kscience.kmath.nd.one
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
 import space.kscience.kmath.tensors.core.randomNormal
 import space.kscience.kmath.tensors.core.tensorAlgebra
@@ -37,7 +37,7 @@ internal class MultikNDTest {
             tensor1 dot tensor2
         }
 
-        val defaultResult = with(DoubleField.tensorAlgebra) {
+        val defaultResult = with(Float64Field.tensorAlgebra) {
             tensor1 dot tensor2
         }
 
diff --git a/kmath-nd4j/README.md b/kmath-nd4j/README.md
index b299c1b37..c2e0cafe0 100644
--- a/kmath-nd4j/README.md
+++ b/kmath-nd4j/README.md
@@ -9,19 +9,8 @@ ND4J based implementations of KMath abstractions.
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-nd4j:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -30,7 +19,7 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-nd4j:0.4.0-dev-1")
+    implementation("space.kscience:kmath-nd4j:0.4.0")
 }
 ```
 
diff --git a/kmath-nd4j/api/kmath-nd4j.api b/kmath-nd4j/api/kmath-nd4j.api
new file mode 100644
index 000000000..5a9a7985d
--- /dev/null
+++ b/kmath-nd4j/api/kmath-nd4j.api
@@ -0,0 +1,394 @@
+public final class space/kscience/kmath/nd4j/DoubleNd4jArrayField : space/kscience/kmath/nd4j/DoubleNd4jArrayFieldOps, space/kscience/kmath/nd/FieldND {
+	public synthetic fun <init> ([ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+	public fun getShape-IIYLAfE ()[I
+}
+
+public class space/kscience/kmath/nd4j/DoubleNd4jArrayFieldOps : space/kscience/kmath/nd4j/Nd4jArrayExtendedFieldOps {
+	public static final field Companion Lspace/kscience/kmath/nd4j/DoubleNd4jArrayFieldOps$Companion;
+	public fun <init> ()V
+	public fun div (DLspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun div (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun div (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun div (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun getElementAlgebra ()Lspace/kscience/kmath/operations/Algebra;
+	public fun getElementAlgebra ()Lspace/kscience/kmath/operations/Float64Field;
+	public fun getNdArray (Lspace/kscience/kmath/nd/StructureND;)Lorg/nd4j/linalg/api/ndarray/INDArray;
+	public fun minus (DLspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun minus (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun minus (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun minus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
+	public fun plus (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun plus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object;
+	public synthetic fun scale (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/StructureND;
+	public fun scale (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public fun times (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun times (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
+	public fun wrap (Lorg/nd4j/linalg/api/ndarray/INDArray;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+}
+
+public final class space/kscience/kmath/nd4j/DoubleNd4jArrayFieldOps$Companion : space/kscience/kmath/nd4j/DoubleNd4jArrayFieldOps {
+}
+
+public final class space/kscience/kmath/nd4j/DoubleNd4jTensorAlgebra : space/kscience/kmath/nd4j/Nd4jTensorAlgebra {
+	public static final field INSTANCE Lspace/kscience/kmath/nd4j/DoubleNd4jTensorAlgebra;
+	public fun diagonalEmbedding (Lspace/kscience/kmath/nd/StructureND;III)Lspace/kscience/kmath/nd/MutableStructureND;
+	public synthetic fun getElementAlgebra ()Lspace/kscience/kmath/operations/Algebra;
+	public fun getElementAlgebra ()Lspace/kscience/kmath/operations/Float64Field;
+	public fun getNdArray (Lspace/kscience/kmath/nd/StructureND;)Lorg/nd4j/linalg/api/ndarray/INDArray;
+	public fun max (Lspace/kscience/kmath/nd/StructureND;)Ljava/lang/Double;
+	public synthetic fun max (Lspace/kscience/kmath/nd/StructureND;)Ljava/lang/Object;
+	public fun mean (Lspace/kscience/kmath/nd/StructureND;)Ljava/lang/Double;
+	public synthetic fun mean (Lspace/kscience/kmath/nd/StructureND;)Ljava/lang/Object;
+	public fun min (Lspace/kscience/kmath/nd/StructureND;)Ljava/lang/Double;
+	public synthetic fun min (Lspace/kscience/kmath/nd/StructureND;)Ljava/lang/Object;
+	public synthetic fun mutableStructureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun mutableStructureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public fun std (Lspace/kscience/kmath/nd/StructureND;)Ljava/lang/Double;
+	public synthetic fun std (Lspace/kscience/kmath/nd/StructureND;)Ljava/lang/Object;
+	public fun sum (Lspace/kscience/kmath/nd/StructureND;)Ljava/lang/Double;
+	public synthetic fun sum (Lspace/kscience/kmath/nd/StructureND;)Ljava/lang/Object;
+	public fun valueOrNull (Lspace/kscience/kmath/nd/StructureND;)Ljava/lang/Double;
+	public synthetic fun valueOrNull (Lspace/kscience/kmath/nd/StructureND;)Ljava/lang/Object;
+	public fun variance (Lspace/kscience/kmath/nd/StructureND;)Ljava/lang/Double;
+	public synthetic fun variance (Lspace/kscience/kmath/nd/StructureND;)Ljava/lang/Object;
+	public fun wrap (Lorg/nd4j/linalg/api/ndarray/INDArray;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+}
+
+public final class space/kscience/kmath/nd4j/FloatNd4jArrayField : space/kscience/kmath/nd4j/FloatNd4jArrayFieldOps, space/kscience/kmath/nd/RingND {
+	public synthetic fun <init> ([ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+	public fun getShape-IIYLAfE ()[I
+}
+
+public class space/kscience/kmath/nd4j/FloatNd4jArrayFieldOps : space/kscience/kmath/nd4j/Nd4jArrayExtendedFieldOps {
+	public static final field Companion Lspace/kscience/kmath/nd4j/FloatNd4jArrayFieldOps$Companion;
+	public fun <init> ()V
+	public fun div (FLspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun div (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun div (Lspace/kscience/kmath/nd/StructureND;F)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun div (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun getElementAlgebra ()Lspace/kscience/kmath/operations/Algebra;
+	public fun getElementAlgebra ()Lspace/kscience/kmath/operations/Float32Field;
+	public fun getNdArray (Lspace/kscience/kmath/nd/StructureND;)Lorg/nd4j/linalg/api/ndarray/INDArray;
+	public fun minus (FLspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun minus (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun minus (Lspace/kscience/kmath/nd/StructureND;F)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun minus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
+	public fun plus (Lspace/kscience/kmath/nd/StructureND;F)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun plus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object;
+	public fun scale (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/StructureND;
+	public fun times (Lspace/kscience/kmath/nd/StructureND;F)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun times (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
+	public fun wrap (Lorg/nd4j/linalg/api/ndarray/INDArray;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+}
+
+public final class space/kscience/kmath/nd4j/FloatNd4jArrayFieldOps$Companion : space/kscience/kmath/nd4j/FloatNd4jArrayFieldOps {
+}
+
+public final class space/kscience/kmath/nd4j/IntNd4jArrayRing : space/kscience/kmath/nd4j/IntNd4jArrayRingOps, space/kscience/kmath/nd/RingND {
+	public synthetic fun <init> ([ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+	public fun getShape-IIYLAfE ()[I
+}
+
+public class space/kscience/kmath/nd4j/IntNd4jArrayRingOps : space/kscience/kmath/nd4j/Nd4jArrayRingOps {
+	public static final field Companion Lspace/kscience/kmath/nd4j/IntNd4jArrayRingOps$Companion;
+	public fun <init> ()V
+	public synthetic fun getElementAlgebra ()Lspace/kscience/kmath/operations/Algebra;
+	public fun getElementAlgebra ()Lspace/kscience/kmath/operations/Int32Ring;
+	public fun getNdArray (Lspace/kscience/kmath/nd/StructureND;)Lorg/nd4j/linalg/api/ndarray/INDArray;
+	public fun minus (ILspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun minus (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun minus (Lspace/kscience/kmath/nd/StructureND;I)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun minus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
+	public fun plus (Lspace/kscience/kmath/nd/StructureND;I)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun plus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
+	public fun times (Lspace/kscience/kmath/nd/StructureND;I)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun times (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
+	public fun wrap (Lorg/nd4j/linalg/api/ndarray/INDArray;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+}
+
+public final class space/kscience/kmath/nd4j/IntNd4jArrayRingOps$Companion : space/kscience/kmath/nd4j/IntNd4jArrayRingOps {
+}
+
+public abstract interface class space/kscience/kmath/nd4j/Nd4jArrayAlgebra : space/kscience/kmath/nd/AlgebraND {
+	public abstract fun getNdArray (Lspace/kscience/kmath/nd/StructureND;)Lorg/nd4j/linalg/api/ndarray/INDArray;
+	public synthetic fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND;
+	public fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND;
+	public fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun mutableStructureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun mutableStructureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public abstract fun wrap (Lorg/nd4j/linalg/api/ndarray/INDArray;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun zip (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND;
+	public fun zip (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+}
+
+public final class space/kscience/kmath/nd4j/Nd4jArrayAlgebraKt {
+	public static final fun getNd4j (Lspace/kscience/kmath/operations/Float32Field;)Lspace/kscience/kmath/nd4j/FloatNd4jArrayFieldOps;
+	public static final fun getNd4j (Lspace/kscience/kmath/operations/Float64Field;)Lspace/kscience/kmath/nd4j/DoubleNd4jArrayFieldOps;
+	public static final fun getNd4j (Lspace/kscience/kmath/operations/Int32Ring;)Lspace/kscience/kmath/nd4j/IntNd4jArrayRingOps;
+	public static final fun nd4j (Lspace/kscience/kmath/operations/Float32Field;I[I)Lspace/kscience/kmath/nd4j/FloatNd4jArrayField;
+	public static final fun nd4j (Lspace/kscience/kmath/operations/Float64Field;I[I)Lspace/kscience/kmath/nd4j/DoubleNd4jArrayField;
+	public static final fun nd4j (Lspace/kscience/kmath/operations/Int32Ring;I[I)Lspace/kscience/kmath/nd4j/IntNd4jArrayRing;
+}
+
+public final class space/kscience/kmath/nd4j/Nd4jArrayDoubleStructure : space/kscience/kmath/nd4j/Nd4jArrayStructure, space/kscience/kmath/nd/StructureNDOfDouble {
+	public fun <init> (Lorg/nd4j/linalg/api/ndarray/INDArray;)V
+	public final fun component1 ()Lorg/nd4j/linalg/api/ndarray/INDArray;
+	public final fun copy (Lorg/nd4j/linalg/api/ndarray/INDArray;)Lspace/kscience/kmath/nd4j/Nd4jArrayDoubleStructure;
+	public static synthetic fun copy$default (Lspace/kscience/kmath/nd4j/Nd4jArrayDoubleStructure;Lorg/nd4j/linalg/api/ndarray/INDArray;ILjava/lang/Object;)Lspace/kscience/kmath/nd4j/Nd4jArrayDoubleStructure;
+	public fun equals (Ljava/lang/Object;)Z
+	public fun get ([I)Ljava/lang/Double;
+	public synthetic fun get ([I)Ljava/lang/Object;
+	public fun getDouble ([I)D
+	public fun getNdArray ()Lorg/nd4j/linalg/api/ndarray/INDArray;
+	public fun hashCode ()I
+	public fun set ([ID)V
+	public synthetic fun set ([ILjava/lang/Object;)V
+	public fun toString ()Ljava/lang/String;
+}
+
+public abstract interface class space/kscience/kmath/nd4j/Nd4jArrayExtendedFieldOps : space/kscience/kmath/nd4j/Nd4jArrayField, space/kscience/kmath/operations/ExtendedFieldOps, space/kscience/kmath/operations/PowerOperations {
+	public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun acos (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun acosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun asin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun asinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun atan (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun atanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun cos (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun cosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun exp (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun ln (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
+	public fun power (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun sin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun sinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun sqrt (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun sqrt (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun tanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+}
+
+public abstract interface class space/kscience/kmath/nd4j/Nd4jArrayField : space/kscience/kmath/nd/FieldOpsND, space/kscience/kmath/nd4j/Nd4jArrayRingOps {
+	public static final field Companion Lspace/kscience/kmath/nd4j/Nd4jArrayField$Companion;
+	public fun div (Ljava/lang/Number;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun divide (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun divide (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+}
+
+public final class space/kscience/kmath/nd4j/Nd4jArrayField$Companion {
+}
+
+public final class space/kscience/kmath/nd4j/Nd4jArrayFloatStructure : space/kscience/kmath/nd4j/Nd4jArrayStructure {
+	public fun <init> (Lorg/nd4j/linalg/api/ndarray/INDArray;)V
+	public final fun component1 ()Lorg/nd4j/linalg/api/ndarray/INDArray;
+	public final fun copy (Lorg/nd4j/linalg/api/ndarray/INDArray;)Lspace/kscience/kmath/nd4j/Nd4jArrayFloatStructure;
+	public static synthetic fun copy$default (Lspace/kscience/kmath/nd4j/Nd4jArrayFloatStructure;Lorg/nd4j/linalg/api/ndarray/INDArray;ILjava/lang/Object;)Lspace/kscience/kmath/nd4j/Nd4jArrayFloatStructure;
+	public fun equals (Ljava/lang/Object;)Z
+	public fun get ([I)Ljava/lang/Float;
+	public synthetic fun get ([I)Ljava/lang/Object;
+	public fun getNdArray ()Lorg/nd4j/linalg/api/ndarray/INDArray;
+	public fun hashCode ()I
+	public fun set ([IF)V
+	public synthetic fun set ([ILjava/lang/Object;)V
+	public fun toString ()Ljava/lang/String;
+}
+
+public abstract interface class space/kscience/kmath/nd4j/Nd4jArrayGroupOps : space/kscience/kmath/nd/GroupOpsND, space/kscience/kmath/nd4j/Nd4jArrayAlgebra {
+	public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun add (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun add (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun minus (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public fun multiply (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun unaryMinus (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+}
+
+public final class space/kscience/kmath/nd4j/Nd4jArrayIntStructure : space/kscience/kmath/nd4j/Nd4jArrayStructure, space/kscience/kmath/nd/StructureNDOfInt {
+	public fun <init> (Lorg/nd4j/linalg/api/ndarray/INDArray;)V
+	public final fun component1 ()Lorg/nd4j/linalg/api/ndarray/INDArray;
+	public final fun copy (Lorg/nd4j/linalg/api/ndarray/INDArray;)Lspace/kscience/kmath/nd4j/Nd4jArrayIntStructure;
+	public static synthetic fun copy$default (Lspace/kscience/kmath/nd4j/Nd4jArrayIntStructure;Lorg/nd4j/linalg/api/ndarray/INDArray;ILjava/lang/Object;)Lspace/kscience/kmath/nd4j/Nd4jArrayIntStructure;
+	public fun equals (Ljava/lang/Object;)Z
+	public fun get ([I)Ljava/lang/Integer;
+	public synthetic fun get ([I)Ljava/lang/Object;
+	public fun getInt ([I)I
+	public fun getNdArray ()Lorg/nd4j/linalg/api/ndarray/INDArray;
+	public fun hashCode ()I
+	public fun set ([II)V
+	public synthetic fun set ([ILjava/lang/Object;)V
+	public fun toString ()Ljava/lang/String;
+}
+
+public abstract interface class space/kscience/kmath/nd4j/Nd4jArrayRingOps : space/kscience/kmath/nd/RingOpsND, space/kscience/kmath/nd4j/Nd4jArrayGroupOps {
+	public static final field Companion Lspace/kscience/kmath/nd4j/Nd4jArrayRingOps$Companion;
+	public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun multiply (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun multiply (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+}
+
+public final class space/kscience/kmath/nd4j/Nd4jArrayRingOps$Companion {
+}
+
+public abstract class space/kscience/kmath/nd4j/Nd4jArrayStructure : space/kscience/kmath/nd/MutableStructureND {
+	public fun elements ()Lkotlin/sequences/Sequence;
+	public abstract fun getNdArray ()Lorg/nd4j/linalg/api/ndarray/INDArray;
+	public fun getShape-IIYLAfE ()[I
+}
+
+public final class space/kscience/kmath/nd4j/Nd4jArrayStructureKt {
+	public static final fun asDoubleStructure (Lorg/nd4j/linalg/api/ndarray/INDArray;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public static final fun asFloatStructure (Lorg/nd4j/linalg/api/ndarray/INDArray;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public static final fun asIntStructure (Lorg/nd4j/linalg/api/ndarray/INDArray;)Lspace/kscience/kmath/nd4j/Nd4jArrayIntStructure;
+}
+
+public abstract interface class space/kscience/kmath/nd4j/Nd4jTensorAlgebra : space/kscience/kmath/tensors/api/AnalyticTensorAlgebra {
+	public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun acos (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun acos (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun acosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun acosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public fun argMax (Lspace/kscience/kmath/nd/StructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun argMin (Lspace/kscience/kmath/nd/StructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND;
+	public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun asin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun asin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun asinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun asinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun atan (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun atan (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun atanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun atanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun ceil (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun ceil (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun cos (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun cos (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun cosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun cosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public fun div (Ljava/lang/Number;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun div (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun div (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public synthetic fun div (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun div (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun div (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public synthetic fun div (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun div (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun div (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public fun divAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Number;)V
+	public synthetic fun divAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V
+	public fun divAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/StructureND;)V
+	public synthetic fun dot (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun dot (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun exp (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun exp (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun floor (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun floor (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public abstract fun getNdArray (Lspace/kscience/kmath/nd/StructureND;)Lorg/nd4j/linalg/api/ndarray/INDArray;
+	public synthetic fun getTensor (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun getTensor (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun ln (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun ln (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND;
+	public fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND;
+	public fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun max (Lspace/kscience/kmath/nd/StructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun max (Lspace/kscience/kmath/nd/StructureND;IZ)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public fun mean (Lspace/kscience/kmath/nd/StructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND;
+	public synthetic fun min (Lspace/kscience/kmath/nd/StructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun min (Lspace/kscience/kmath/nd/StructureND;IZ)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public fun minus (Ljava/lang/Number;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun minus (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public synthetic fun minus (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun minus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun minus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public synthetic fun minus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun minus (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun minus (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public fun minusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Number;)V
+	public synthetic fun minusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V
+	public fun minusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/StructureND;)V
+	public abstract fun mutableStructureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public fun plus (Ljava/lang/Number;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun plus (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public synthetic fun plus (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun plus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun plus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public synthetic fun plus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun plus (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun plus (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public fun plusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Number;)V
+	public synthetic fun plusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V
+	public fun plusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/StructureND;)V
+	public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
+	public fun power (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun sin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun sin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun sinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public synthetic fun sinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun sqrt (Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun sqrt (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun sqrt (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public fun std (Lspace/kscience/kmath/nd/StructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND;
+	public synthetic fun sum (Lspace/kscience/kmath/nd/StructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun sum (Lspace/kscience/kmath/nd/StructureND;IZ)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun tan (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun tan (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun tanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun tanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public fun times (Ljava/lang/Number;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun times (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public synthetic fun times (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND;
+	public fun times (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun times (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public synthetic fun times (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
+	public synthetic fun times (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun times (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public fun timesAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Number;)V
+	public synthetic fun timesAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V
+	public fun timesAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/StructureND;)V
+	public synthetic fun transposed (Lspace/kscience/kmath/nd/StructureND;II)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun transposed (Lspace/kscience/kmath/nd/StructureND;II)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun unaryMinus (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun unaryMinus (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public fun variance (Lspace/kscience/kmath/nd/StructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND;
+	public synthetic fun view-waz_sdI (Lspace/kscience/kmath/nd/MutableStructureND;[I)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun view-waz_sdI (Lspace/kscience/kmath/nd/MutableStructureND;[I)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun viewAs (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun viewAs (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public abstract fun wrap (Lorg/nd4j/linalg/api/ndarray/INDArray;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+	public synthetic fun zip (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND;
+	public fun zip (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd4j/Nd4jArrayStructure;
+}
+
diff --git a/kmath-nd4j/build.gradle.kts b/kmath-nd4j/build.gradle.kts
index e5c4af891..bfa09e771 100644
--- a/kmath-nd4j/build.gradle.kts
+++ b/kmath-nd4j/build.gradle.kts
@@ -12,7 +12,7 @@ dependencies {
 }
 
 readme {
-    maturity = space.kscience.gradle.Maturity.EXPERIMENTAL
+    maturity = space.kscience.gradle.Maturity.DEPRECATED
     propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
     feature(id = "nd4jarraystructure") { "NDStructure wrapper for INDArray" }
     feature(id = "nd4jarrayrings") { "Rings over Nd4jArrayStructure of Int and Long" }
diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt
index 0eb147b6f..648e5e318 100644
--- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt
+++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -34,7 +34,7 @@ public sealed interface Nd4jArrayAlgebra<T, out C : Algebra<T>> : AlgebraND<T, C
     public val StructureND<T>.ndArray: INDArray
 
     @OptIn(PerformancePitfall::class)
-    override fun structureND(shape: ShapeND, initializer: C.(IntArray) -> T): Nd4jArrayStructure<T> {
+    override fun mutableStructureND(shape: ShapeND, initializer: C.(IntArray) -> T): Nd4jArrayStructure<T> {
         @OptIn(UnsafeKMathAPI::class)
         val struct: Nd4jArrayStructure<T> = Nd4j.create(*shape.asArray())!!.wrap()
         struct.indicesIterator().forEach { struct[it] = elementAlgebra.initializer(it) }
@@ -124,7 +124,7 @@ public sealed interface Nd4jArrayRingOps<T, out R : Ring<T>> : RingOpsND<T, R>,
          */
         @Suppress("UNCHECKED_CAST")
         public inline fun <reified T : Number> auto(): Nd4jArrayRingOps<T, Ring<T>> = when {
-            T::class == Int::class -> IntRing.nd4j as Nd4jArrayRingOps<T, Ring<T>>
+            T::class == Int::class -> Int32Ring.nd4j as Nd4jArrayRingOps<T, Ring<T>>
             else -> throw UnsupportedOperationException("This factory method only supports Long type.")
         }
     }
@@ -149,8 +149,8 @@ public sealed interface Nd4jArrayField<T, out F : Field<T>> : FieldOpsND<T, F>,
          */
         @Suppress("UNCHECKED_CAST")
         public inline fun <reified T : Any> auto(): Nd4jArrayField<T, Field<T>> = when {
-            T::class == Float::class -> FloatField.nd4j as Nd4jArrayField<T, Field<T>>
-            T::class == Double::class -> DoubleField.nd4j as Nd4jArrayField<T, Field<T>>
+            T::class == Float::class -> Float32Field.nd4j as Nd4jArrayField<T, Field<T>>
+            T::class == Double::class -> Float64Field.nd4j as Nd4jArrayField<T, Field<T>>
             else -> throw UnsupportedOperationException("This factory method only supports Float and Double types.")
         }
     }
@@ -190,8 +190,8 @@ public sealed interface Nd4jArrayExtendedFieldOps<T, out F : ExtendedField<T>> :
 /**
  * Represents [FieldND] over [Nd4jArrayDoubleStructure].
  */
-public open class DoubleNd4jArrayFieldOps : Nd4jArrayExtendedFieldOps<Double, DoubleField> {
-    override val elementAlgebra: DoubleField get() = DoubleField
+public open class DoubleNd4jArrayFieldOps : Nd4jArrayExtendedFieldOps<Double, Float64Field> {
+    override val elementAlgebra: Float64Field get() = Float64Field
 
     override fun INDArray.wrap(): Nd4jArrayStructure<Double> = asDoubleStructure()
 
@@ -223,19 +223,20 @@ public open class DoubleNd4jArrayFieldOps : Nd4jArrayExtendedFieldOps<Double, Do
     public companion object : DoubleNd4jArrayFieldOps()
 }
 
-public val DoubleField.nd4j: DoubleNd4jArrayFieldOps get() = DoubleNd4jArrayFieldOps
+public val Float64Field.nd4j: DoubleNd4jArrayFieldOps get() = DoubleNd4jArrayFieldOps
 
-public class DoubleNd4jArrayField(override val shape: ShapeND) : DoubleNd4jArrayFieldOps(), FieldND<Double, DoubleField>
+public class DoubleNd4jArrayField(override val shape: ShapeND) : DoubleNd4jArrayFieldOps(),
+    FieldND<Double, Float64Field>
 
-public fun DoubleField.nd4j(shapeFirst: Int, vararg shapeRest: Int): DoubleNd4jArrayField =
+public fun Float64Field.nd4j(shapeFirst: Int, vararg shapeRest: Int): DoubleNd4jArrayField =
     DoubleNd4jArrayField(ShapeND(shapeFirst, * shapeRest))
 
 
 /**
  * Represents [FieldND] over [Nd4jArrayStructure] of [Float].
  */
-public open class FloatNd4jArrayFieldOps : Nd4jArrayExtendedFieldOps<Float, FloatField> {
-    override val elementAlgebra: FloatField get() = FloatField
+public open class FloatNd4jArrayFieldOps : Nd4jArrayExtendedFieldOps<Float, Float32Field> {
+    override val elementAlgebra: Float32Field get() = Float32Field
 
     override fun INDArray.wrap(): Nd4jArrayStructure<Float> = asFloatStructure()
 
@@ -272,18 +273,18 @@ public open class FloatNd4jArrayFieldOps : Nd4jArrayExtendedFieldOps<Float, Floa
     public companion object : FloatNd4jArrayFieldOps()
 }
 
-public class FloatNd4jArrayField(override val shape: ShapeND) : FloatNd4jArrayFieldOps(), RingND<Float, FloatField>
+public class FloatNd4jArrayField(override val shape: ShapeND) : FloatNd4jArrayFieldOps(), RingND<Float, Float32Field>
 
-public val FloatField.nd4j: FloatNd4jArrayFieldOps get() = FloatNd4jArrayFieldOps
+public val Float32Field.nd4j: FloatNd4jArrayFieldOps get() = FloatNd4jArrayFieldOps
 
-public fun FloatField.nd4j(shapeFirst: Int, vararg shapeRest: Int): FloatNd4jArrayField =
+public fun Float32Field.nd4j(shapeFirst: Int, vararg shapeRest: Int): FloatNd4jArrayField =
     FloatNd4jArrayField(ShapeND(shapeFirst, * shapeRest))
 
 /**
  * Represents [RingND] over [Nd4jArrayIntStructure].
  */
-public open class IntNd4jArrayRingOps : Nd4jArrayRingOps<Int, IntRing> {
-    override val elementAlgebra: IntRing get() = IntRing
+public open class IntNd4jArrayRingOps : Nd4jArrayRingOps<Int, Int32Ring> {
+    override val elementAlgebra: Int32Ring get() = Int32Ring
 
     override fun INDArray.wrap(): Nd4jArrayStructure<Int> = asIntStructure()
 
@@ -311,9 +312,9 @@ public open class IntNd4jArrayRingOps : Nd4jArrayRingOps<Int, IntRing> {
     public companion object : IntNd4jArrayRingOps()
 }
 
-public val IntRing.nd4j: IntNd4jArrayRingOps get() = IntNd4jArrayRingOps
+public val Int32Ring.nd4j: IntNd4jArrayRingOps get() = IntNd4jArrayRingOps
 
-public class IntNd4jArrayRing(override val shape: ShapeND) : IntNd4jArrayRingOps(), RingND<Int, IntRing>
+public class IntNd4jArrayRing(override val shape: ShapeND) : IntNd4jArrayRingOps(), RingND<Int, Int32Ring>
 
-public fun IntRing.nd4j(shapeFirst: Int, vararg shapeRest: Int): IntNd4jArrayRing =
+public fun Int32Ring.nd4j(shapeFirst: Int, vararg shapeRest: Int): IntNd4jArrayRing =
     IntNd4jArrayRing(ShapeND(shapeFirst, * shapeRest))
\ No newline at end of file
diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt
index fedad26e0..0a2305e71 100644
--- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt
+++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt
index 93fbc8f85..ac4ef68d2 100644
--- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt
+++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -31,6 +31,7 @@ public sealed class Nd4jArrayStructure<T> : MutableStructureND<T> {
 }
 
 public data class Nd4jArrayIntStructure(override val ndArray: INDArray) : Nd4jArrayStructure<Int>(), StructureNDOfInt {
+
     override fun elementsIterator(): Iterator<Pair<IntArray, Int>> = ndArray.intIterator()
 
     @OptIn(PerformancePitfall::class)
@@ -47,8 +48,10 @@ public data class Nd4jArrayIntStructure(override val ndArray: INDArray) : Nd4jAr
  */
 public fun INDArray.asIntStructure(): Nd4jArrayIntStructure = Nd4jArrayIntStructure(this)
 
-public data class Nd4jArrayDoubleStructure(override val ndArray: INDArray) : Nd4jArrayStructure<Double>(), StructureNDOfDouble {
+public data class Nd4jArrayDoubleStructure(override val ndArray: INDArray) : Nd4jArrayStructure<Double>(),
+    StructureNDOfDouble {
     override fun elementsIterator(): Iterator<Pair<IntArray, Double>> = ndArray.realIterator()
+
     @OptIn(PerformancePitfall::class)
     override fun get(index: IntArray): Double = ndArray.getDouble(*index)
 
@@ -64,7 +67,9 @@ public data class Nd4jArrayDoubleStructure(override val ndArray: INDArray) : Nd4
 public fun INDArray.asDoubleStructure(): Nd4jArrayStructure<Double> = Nd4jArrayDoubleStructure(this)
 
 public data class Nd4jArrayFloatStructure(override val ndArray: INDArray) : Nd4jArrayStructure<Float>() {
+
     override fun elementsIterator(): Iterator<Pair<IntArray, Float>> = ndArray.floatIterator()
+
     @PerformancePitfall
     override fun get(index: IntArray): Float = ndArray.getFloat(*index)
 
diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt
index 5905739f8..095715070 100644
--- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt
+++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -15,8 +15,8 @@ import org.nd4j.linalg.ops.transforms.Transforms
 import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.UnsafeKMathAPI
 import space.kscience.kmath.nd.*
-import space.kscience.kmath.operations.DoubleField
 import space.kscience.kmath.operations.Field
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra
 import space.kscience.kmath.tensors.api.Tensor
 import space.kscience.kmath.tensors.api.TensorAlgebra
@@ -37,20 +37,20 @@ public sealed interface Nd4jTensorAlgebra<T : Number, A : Field<T>> : AnalyticTe
      */
     public val StructureND<T>.ndArray: INDArray
 
-    override fun structureND(shape: ShapeND, initializer: A.(IntArray) -> T): Nd4jArrayStructure<T>
+    override fun mutableStructureND(shape: ShapeND, initializer: A.(IntArray) -> T): Nd4jArrayStructure<T>
 
     @OptIn(PerformancePitfall::class)
     override fun StructureND<T>.map(transform: A.(T) -> T): Nd4jArrayStructure<T> =
-        structureND(shape) { index -> elementAlgebra.transform(get(index)) }
+        mutableStructureND(shape) { index -> elementAlgebra.transform(get(index)) }
 
     @OptIn(PerformancePitfall::class)
     override fun StructureND<T>.mapIndexed(transform: A.(index: IntArray, T) -> T): Nd4jArrayStructure<T> =
-        structureND(shape) { index -> elementAlgebra.transform(index, get(index)) }
+        mutableStructureND(shape) { index -> elementAlgebra.transform(index, get(index)) }
 
     @OptIn(PerformancePitfall::class)
     override fun zip(left: StructureND<T>, right: StructureND<T>, transform: A.(T, T) -> T): Nd4jArrayStructure<T> {
         require(left.shape.contentEquals(right.shape))
-        return structureND(left.shape) { index -> elementAlgebra.transform(left[index], right[index]) }
+        return mutableStructureND(left.shape) { index -> elementAlgebra.transform(left[index], right[index]) }
     }
 
     override fun T.plus(arg: StructureND<T>): Nd4jArrayStructure<T> = arg.ndArray.add(this).wrap()
@@ -144,7 +144,9 @@ public sealed interface Nd4jTensorAlgebra<T : Number, A : Field<T>> : AnalyticTe
     override fun atanh(arg: StructureND<T>): Nd4jArrayStructure<T> = Transforms.atanh(arg.ndArray).wrap()
     override fun power(arg: StructureND<T>, pow: Number): StructureND<T> = Transforms.pow(arg.ndArray, pow).wrap()
     override fun ceil(arg: StructureND<T>): Nd4jArrayStructure<T> = Transforms.ceil(arg.ndArray).wrap()
-    override fun floor(structureND: StructureND<T>): Nd4jArrayStructure<T> = Transforms.floor(structureND.ndArray).wrap()
+    override fun floor(structureND: StructureND<T>): Nd4jArrayStructure<T> =
+        Transforms.floor(structureND.ndArray).wrap()
+
     override fun std(structureND: StructureND<T>, dim: Int, keepDim: Boolean): Tensor<T> =
         structureND.ndArray.std(true, keepDim, dim).wrap()
 
@@ -171,14 +173,17 @@ public sealed interface Nd4jTensorAlgebra<T : Number, A : Field<T>> : AnalyticTe
 /**
  * [Double] specialization of [Nd4jTensorAlgebra].
  */
-public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra<Double, DoubleField> {
+public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra<Double, Float64Field> {
 
-    override val elementAlgebra: DoubleField get() = DoubleField
+    override val elementAlgebra: Float64Field get() = Float64Field
 
     override fun INDArray.wrap(): Nd4jArrayStructure<Double> = asDoubleStructure()
 
     @OptIn(UnsafeKMathAPI::class)
-    override fun structureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): Nd4jArrayStructure<Double> {
+    override fun mutableStructureND(
+        shape: ShapeND,
+        initializer: Float64Field.(IntArray) -> Double,
+    ): Nd4jArrayStructure<Double> {
         val array: INDArray = Nd4j.zeros(*shape.asArray())
         val indices = ColumnStrides(shape)
         indices.asSequence().forEach { index ->
diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt
index 401c57a7b..8f02f3c55 100644
--- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt
+++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt
index 708778e77..042dd72ac 100644
--- a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt
+++ b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -10,8 +10,8 @@ import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.nd.StructureND
 import space.kscience.kmath.nd.one
 import space.kscience.kmath.nd.structureND
-import space.kscience.kmath.operations.DoubleField
-import space.kscience.kmath.operations.IntRing
+import space.kscience.kmath.operations.Float64Field
+import space.kscience.kmath.operations.Int32Ring
 import space.kscience.kmath.operations.invoke
 import kotlin.math.PI
 import kotlin.test.Test
@@ -23,7 +23,7 @@ import kotlin.test.fail
 internal class Nd4jArrayAlgebraTest {
     @Test
     fun testProduce() {
-        val res = DoubleField.nd4j.structureND(2, 2) { it.sum().toDouble() }
+        val res = Float64Field.nd4j.structureND(2, 2) { it.sum().toDouble() }
         val expected = (Nd4j.create(2, 2) ?: fail()).asDoubleStructure()
         expected[intArrayOf(0, 0)] = 0.0
         expected[intArrayOf(0, 1)] = 1.0
@@ -34,7 +34,7 @@ internal class Nd4jArrayAlgebraTest {
 
     @Test
     fun testMap() {
-        val res = IntRing.nd4j {
+        val res = Int32Ring.nd4j {
             one(2, 2).map { it + it * 2 }
         }
         val expected = (Nd4j.create(2, 2) ?: fail()).asIntStructure()
@@ -47,7 +47,7 @@ internal class Nd4jArrayAlgebraTest {
 
     @Test
     fun testAdd() {
-        val res = IntRing.nd4j { one(2, 2) + 25 }
+        val res = Int32Ring.nd4j { one(2, 2) + 25 }
         val expected = (Nd4j.create(2, 2) ?: fail()).asIntStructure()
         expected[intArrayOf(0, 0)] = 26
         expected[intArrayOf(0, 1)] = 26
@@ -57,7 +57,7 @@ internal class Nd4jArrayAlgebraTest {
     }
 
     @Test
-    fun testSin() = DoubleField.nd4j{
+    fun testSin() = Float64Field.nd4j {
         val initial = structureND(2, 2) { (i, j) -> if (i == j) PI / 2 else 0.0 }
         val transformed = sin(initial)
         val expected = structureND(2, 2) { (i, j) -> if (i == j) 1.0 else 0.0 }
diff --git a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt
index d57eb2e2d..5c3664cb3 100644
--- a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt
+++ b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-optimization/README.md b/kmath-optimization/README.md
index 79a4f5d24..3728ab18e 100644
--- a/kmath-optimization/README.md
+++ b/kmath-optimization/README.md
@@ -6,19 +6,8 @@
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-optimization:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-optimization:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-optimization:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -27,6 +16,6 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-optimization:0.4.0-dev-1")
+    implementation("space.kscience:kmath-optimization:0.4.0")
 }
 ```
diff --git a/kmath-optimization/build.gradle.kts b/kmath-optimization/build.gradle.kts
index 7250d1f72..d69858339 100644
--- a/kmath-optimization/build.gradle.kts
+++ b/kmath-optimization/build.gradle.kts
@@ -2,10 +2,11 @@ plugins {
     id("space.kscience.gradle.mpp")
 }
 
-kscience{
+kscience {
     jvm()
     js()
     native()
+    wasm()
 }
 
 kotlin.sourceSets {
diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt
index 07146625c..263576d77 100644
--- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt
+++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt
@@ -1,28 +1,33 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.optimization
 
+import space.kscience.attributes.*
 import space.kscience.kmath.expressions.DifferentiableExpression
 import space.kscience.kmath.expressions.Symbol
-import space.kscience.kmath.misc.FeatureSet
 
-public class OptimizationValue<T>(public val value: T) : OptimizationFeature {
-    override fun toString(): String = "Value($value)"
+public class OptimizationValue<V>(type: SafeType<V>) : PolymorphicAttribute<V>(type)
+
+public inline fun <reified T> AttributesBuilder<FunctionOptimization<T>>.value(value: T) {
+    set(OptimizationValue(safeTypeOf<T>()), value)
 }
 
-public enum class FunctionOptimizationTarget : OptimizationFeature {
+public enum class OptimizationDirection {
     MAXIMIZE,
     MINIMIZE
 }
 
+public object FunctionOptimizationTarget : OptimizationAttribute<OptimizationDirection>
+
 public class FunctionOptimization<T>(
-    override val features: FeatureSet<OptimizationFeature>,
     public val expression: DifferentiableExpression<T>,
+    override val attributes: Attributes,
 ) : OptimizationProblem<T> {
 
+    override val type: SafeType<T> get() = expression.type
 
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
@@ -30,42 +35,69 @@ public class FunctionOptimization<T>(
 
         other as FunctionOptimization<*>
 
-        if (features != other.features) return false
+        if (attributes != other.attributes) return false
         if (expression != other.expression) return false
 
         return true
     }
 
     override fun hashCode(): Int {
-        var result = features.hashCode()
+        var result = attributes.hashCode()
         result = 31 * result + expression.hashCode()
         return result
     }
 
-    override fun toString(): String = "FunctionOptimization(features=$features)"
+    override fun toString(): String = "FunctionOptimization(attributes=$attributes)"
+
+    public companion object
 }
 
-public fun <T> FunctionOptimization<T>.withFeatures(
-    vararg newFeature: OptimizationFeature,
+public fun <T> FunctionOptimization(
+    expression: DifferentiableExpression<T>,
+    attributeBuilder: AttributesBuilder<FunctionOptimization<T>>.() -> Unit,
+): FunctionOptimization<T> = FunctionOptimization(expression, Attributes(attributeBuilder))
+
+public class OptimizationPrior<T> :
+    PolymorphicAttribute<DifferentiableExpression<T>>(safeTypeOf()),
+    Attribute<DifferentiableExpression<T>>
+
+public fun <T> FunctionOptimization<T>.withAttributes(
+    modifier: AttributesBuilder<FunctionOptimization<T>>.() -> Unit,
 ): FunctionOptimization<T> = FunctionOptimization(
-    features.with(*newFeature),
     expression,
+    attributes.modified(modifier),
 )
 
 /**
  * Optimizes differentiable expression using specific [optimizer] form given [startingPoint].
  */
-public suspend fun <T : Any> DifferentiableExpression<T>.optimizeWith(
+public suspend fun <T> DifferentiableExpression<T>.optimizeWith(
     optimizer: Optimizer<T, FunctionOptimization<T>>,
     startingPoint: Map<Symbol, T>,
-    vararg features: OptimizationFeature,
+    modifier: AttributesBuilder<FunctionOptimization<T>>.() -> Unit = {},
 ): FunctionOptimization<T> {
-    val problem = FunctionOptimization<T>(FeatureSet.of(OptimizationStartPoint(startingPoint), *features), this)
+    val problem = FunctionOptimization(this) {
+        startAt(startingPoint)
+        modifier()
+    }
     return optimizer.optimize(problem)
 }
 
 public val <T> FunctionOptimization<T>.resultValueOrNull: T?
-    get() = getFeature<OptimizationResult<T>>()?.point?.let { expression(it) }
+    get() = attributes[OptimizationResult<T>()]?.let { expression(it) }
 
 public val <T> FunctionOptimization<T>.resultValue: T
-    get() = resultValueOrNull ?: error("Result is not present in $this")
\ No newline at end of file
+    get() = resultValueOrNull ?: error("Result is not present in $this")
+
+
+public suspend fun <T> DifferentiableExpression<T>.optimizeWith(
+    optimizer: Optimizer<T, FunctionOptimization<T>>,
+    vararg startingPoint: Pair<Symbol, T>,
+    builder: AttributesBuilder<FunctionOptimization<T>>.() -> Unit = {},
+): FunctionOptimization<T> {
+    val problem = FunctionOptimization<T>(this) {
+        startAt(mapOf(*startingPoint))
+        builder()
+    }
+    return optimizer.optimize(problem)
+}
diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt
deleted file mode 100644
index 0459d46ee..000000000
--- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2018-2022 KMath contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package space.kscience.kmath.optimization
-
-import space.kscience.kmath.UnstableKMathAPI
-import space.kscience.kmath.data.XYColumnarData
-import space.kscience.kmath.expressions.DifferentiableExpression
-import space.kscience.kmath.expressions.Symbol
-import space.kscience.kmath.misc.FeatureSet
-
-public abstract class OptimizationBuilder<T, R : OptimizationProblem<T>> {
-    public val features: MutableList<OptimizationFeature> = ArrayList()
-
-    public fun addFeature(feature: OptimizationFeature) {
-        features.add(feature)
-    }
-
-    public inline fun <reified T : OptimizationFeature> updateFeature(update: (T?) -> T) {
-        val existing = features.find { it.key == T::class } as? T
-        val new = update(existing)
-        if (existing != null) {
-            features.remove(existing)
-        }
-        addFeature(new)
-    }
-
-    public abstract fun build(): R
-}
-
-public fun <T> OptimizationBuilder<T, *>.startAt(startingPoint: Map<Symbol, T>) {
-    addFeature(OptimizationStartPoint(startingPoint))
-}
-
-public class FunctionOptimizationBuilder<T>(
-    private val expression: DifferentiableExpression<T>,
-) : OptimizationBuilder<T, FunctionOptimization<T>>() {
-    override fun build(): FunctionOptimization<T> = FunctionOptimization(FeatureSet.of(features), expression)
-}
-
-public fun <T> FunctionOptimization(
-    expression: DifferentiableExpression<T>,
-    builder: FunctionOptimizationBuilder<T>.() -> Unit,
-): FunctionOptimization<T> = FunctionOptimizationBuilder(expression).apply(builder).build()
-
-public suspend fun <T> DifferentiableExpression<T>.optimizeWith(
-    optimizer: Optimizer<T, FunctionOptimization<T>>,
-    startingPoint: Map<Symbol, T>,
-    builder: FunctionOptimizationBuilder<T>.() -> Unit = {},
-): FunctionOptimization<T> {
-    val problem = FunctionOptimization<T>(this) {
-        startAt(startingPoint)
-        builder()
-    }
-    return optimizer.optimize(problem)
-}
-
-public suspend fun <T> DifferentiableExpression<T>.optimizeWith(
-    optimizer: Optimizer<T, FunctionOptimization<T>>,
-    vararg startingPoint: Pair<Symbol, T>,
-    builder: FunctionOptimizationBuilder<T>.() -> Unit = {},
-): FunctionOptimization<T> {
-    val problem = FunctionOptimization<T>(this) {
-        startAt(mapOf(*startingPoint))
-        builder()
-    }
-    return optimizer.optimize(problem)
-}
-
-
-@OptIn(UnstableKMathAPI::class)
-public class XYOptimizationBuilder(
-    public val data: XYColumnarData<Double, Double, Double>,
-    public val model: DifferentiableExpression<Double>,
-) : OptimizationBuilder<Double, XYFit>() {
-
-    public var pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY
-    public var pointWeight: PointWeight = PointWeight.byYSigma
-
-    override fun build(): XYFit = XYFit(
-        data,
-        model,
-        FeatureSet.of(features),
-        pointToCurveDistance,
-        pointWeight
-    )
-}
-
-@OptIn(UnstableKMathAPI::class)
-public fun XYOptimization(
-    data: XYColumnarData<Double, Double, Double>,
-    model: DifferentiableExpression<Double>,
-    builder: XYOptimizationBuilder.() -> Unit,
-): XYFit = XYOptimizationBuilder(data, model).apply(builder).build()
\ No newline at end of file
diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt
index 9fdcfc53d..2ba80251b 100644
--- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt
+++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt
@@ -1,79 +1,66 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.optimization
 
-import space.kscience.kmath.expressions.DifferentiableExpression
+import space.kscience.attributes.*
 import space.kscience.kmath.expressions.NamedMatrix
 import space.kscience.kmath.expressions.Symbol
-import space.kscience.kmath.misc.*
-import kotlin.reflect.KClass
+import space.kscience.kmath.misc.Loggable
 
-public interface OptimizationFeature : Feature<OptimizationFeature> {
-    // enforce toString override
-    override fun toString(): String
-}
+public interface OptimizationAttribute<T> : Attribute<T>
 
-public interface OptimizationProblem<T> : Featured<OptimizationFeature> {
-    public val features: FeatureSet<OptimizationFeature>
-    override fun <F : OptimizationFeature> getFeature(type: KClass<out F>): F? = features.getFeature(type)
-}
+public interface OptimizationProblem<T> : AttributeContainer, WithType<T>
 
-public inline fun <reified F : OptimizationFeature> OptimizationProblem<*>.getFeature(): F? = getFeature(F::class)
-
-public open class OptimizationStartPoint<T>(public val point: Map<Symbol, T>) : OptimizationFeature {
-    override fun toString(): String = "StartPoint($point)"
-}
-
-
-public interface OptimizationPrior<T> : OptimizationFeature, DifferentiableExpression<T> {
-    override val key: FeatureKey<OptimizationFeature> get() = OptimizationPrior::class
-}
-
-/**
- * Covariance matrix for
- */
-public class OptimizationCovariance<T>(public val covariance: NamedMatrix<T>) : OptimizationFeature {
-    override fun toString(): String = "Covariance($covariance)"
-}
+public class OptimizationStartPoint<T> : OptimizationAttribute<Map<Symbol, T>>,
+    PolymorphicAttribute<Map<Symbol, T>>(safeTypeOf())
 
 /**
  * Get the starting point for optimization. Throws error if not defined.
  */
 public val <T> OptimizationProblem<T>.startPoint: Map<Symbol, T>
-    get() = getFeature<OptimizationStartPoint<T>>()?.point
-        ?: error("Starting point not defined in $this")
+    get() = attributes[OptimizationStartPoint()] ?: error("Starting point not defined in $this")
 
-public open class OptimizationResult<T>(public val point: Map<Symbol, T>) : OptimizationFeature {
-    override fun toString(): String = "Result($point)"
+public fun <T> AttributesBuilder<OptimizationProblem<T>>.startAt(startingPoint: Map<Symbol, T>) {
+    set(OptimizationStartPoint(), startingPoint)
 }
 
-public val <T> OptimizationProblem<T>.resultPointOrNull: Map<Symbol, T>?
-    get() = getFeature<OptimizationResult<T>>()?.point
 
-public val <T> OptimizationProblem<T>.resultPoint: Map<Symbol, T>
-    get() = resultPointOrNull ?: error("Result is not present in $this")
+/**
+ * Covariance matrix for optimization
+ */
+public class OptimizationCovariance<T> : OptimizationAttribute<NamedMatrix<T>>,
+    PolymorphicAttribute<NamedMatrix<T>>(safeTypeOf())
 
-public class OptimizationLog(private val loggable: Loggable) : Loggable by loggable, OptimizationFeature {
-    override fun toString(): String = "Log($loggable)"
+public fun <T> AttributesBuilder<OptimizationProblem<T>>.covariance(covariance: NamedMatrix<T>) {
+    set(OptimizationCovariance(), covariance)
 }
 
+
+public class OptimizationResult<T>() : OptimizationAttribute<Map<Symbol, T>>,
+    PolymorphicAttribute<Map<Symbol, T>>(safeTypeOf())
+
+public fun <T> AttributesBuilder<OptimizationProblem<T>>.result(result: Map<Symbol, T>) {
+    set(OptimizationResult(), result)
+}
+
+public val <T> OptimizationProblem<T>.resultOrNull: Map<Symbol, T>? get() = attributes[OptimizationResult()]
+
+public val <T> OptimizationProblem<T>.result: Map<Symbol, T>
+    get() = resultOrNull ?: error("Result is not present in $this")
+
+public object OptimizationLog : OptimizationAttribute<Loggable>
+
 /**
  * Free parameters of the optimization
  */
-public class OptimizationParameters(public val symbols: List<Symbol>) : OptimizationFeature {
-    public constructor(vararg symbols: Symbol) : this(listOf(*symbols))
-
-    override fun toString(): String = "Parameters($symbols)"
-}
+public object OptimizationParameters : OptimizationAttribute<List<Symbol>>
 
 /**
  * Maximum allowed number of iterations
  */
-public class OptimizationIterations(public val maxIterations: Int) : OptimizationFeature {
-    override fun toString(): String = "Iterations($maxIterations)"
-}
+public object OptimizationIterations : OptimizationAttribute<Int>
 
 
diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt
index 41dcbf770..ed8242929 100644
--- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt
+++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt
index b698584aa..07fa97efb 100644
--- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt
+++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -9,20 +9,14 @@ import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.expressions.*
 import space.kscience.kmath.linear.*
 import space.kscience.kmath.misc.log
-import space.kscience.kmath.operations.DoubleField
-import space.kscience.kmath.operations.DoubleL2Norm
+import space.kscience.kmath.operations.Float64Field
+import space.kscience.kmath.operations.Float64L2Norm
 import space.kscience.kmath.operations.algebra
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import kotlin.math.abs
 
 
-public class QowRuns(public val runs: Int) : OptimizationFeature {
-    init {
-        require(runs >= 1) { "Number of runs must be more than zero" }
-    }
-
-    override fun toString(): String = "QowRuns(runs=$runs)"
-}
+public object QowRuns : OptimizationAttribute<Int>
 
 
 /**
@@ -32,7 +26,7 @@ public class QowRuns(public val runs: Int) : OptimizationFeature {
 @UnstableKMathAPI
 public object QowOptimizer : Optimizer<Double, XYFit> {
 
-    private val linearSpace: LinearSpace<Double, DoubleField> = Double.algebra.linearSpace
+    private val linearSpace: LinearSpace<Double, Float64Field> = Double.algebra.linearSpace
     private val solver: LinearSolver<Double> = linearSpace.lupSolver()
 
     @OptIn(UnstableKMathAPI::class)
@@ -63,13 +57,13 @@ public object QowOptimizer : Optimizer<Double, XYFit> {
          * Array of dispersions in each point
          */
         val dispersion: Point<Double> by lazy {
-            DoubleBuffer(problem.data.size) { d ->
+            Float64Buffer(problem.data.size) { d ->
                 1.0 / problem.weight(d).invoke(allParameters)
             }
         }
 
         val prior: DifferentiableExpression<Double>?
-            get() = problem.getFeature<OptimizationPrior<Double>>()?.withDefaultArgs(allParameters)
+            get() = problem.attributes[OptimizationPrior<Double>()]?.withDefaultArgs(allParameters)
 
         override fun toString(): String = freeParameters.toString()
     }
@@ -148,8 +142,8 @@ public object QowOptimizer : Optimizer<Double, XYFit> {
      * Quasi optimal weights equations values
      */
     private fun QoWeight.getEqValues(theta: Map<Symbol, Double>): Point<Double> {
-        val distances = DoubleBuffer(data.size) { d -> distance(d, theta) }
-        return DoubleBuffer(size) { s ->
+        val distances = Float64Buffer(data.size) { d -> distance(d, theta) }
+        return Float64Buffer(size) { s ->
             val base = (0 until data.size).sumOf { d -> distances[d] * derivs[d, s] / dispersion[d] }
             //Prior probability correction
             prior?.let { prior ->
@@ -176,7 +170,7 @@ public object QowOptimizer : Optimizer<Double, XYFit> {
         fast: Boolean = false,
     ): QoWeight {
 
-        val logger = problem.getFeature<OptimizationLog>()
+        val logger = problem.attributes[OptimizationLog]
 
         var dis: Double //discrepancy value
 
@@ -186,7 +180,7 @@ public object QowOptimizer : Optimizer<Double, XYFit> {
 
         var eqvalues = getEqValues(par) //Values of the weight functions
 
-        dis = DoubleL2Norm.norm(eqvalues) // discrepancy
+        dis = Float64L2Norm.norm(eqvalues) // discrepancy
         logger?.log { "Starting discrepancy is $dis" }
         var i = 0
         var flag = false
@@ -205,7 +199,7 @@ public object QowOptimizer : Optimizer<Double, XYFit> {
             logger?.log { "Parameter values after step are: \n\t$currentSolution" }
 
             eqvalues = getEqValues(currentSolution.freeParameters)
-            val currentDis = DoubleL2Norm.norm(eqvalues)// discrepancy after the step
+            val currentDis = Float64L2Norm.norm(eqvalues)// discrepancy after the step
 
             logger?.log { "The discrepancy after step is: $currentDis." }
 
@@ -231,7 +225,7 @@ public object QowOptimizer : Optimizer<Double, XYFit> {
     }
 
     private fun QoWeight.covariance(): NamedMatrix<Double> {
-        val logger = problem.getFeature<OptimizationLog>()
+        val logger = problem.attributes[OptimizationLog]
 
         logger?.log {
             """
@@ -257,11 +251,11 @@ public object QowOptimizer : Optimizer<Double, XYFit> {
     }
 
     override suspend fun optimize(problem: XYFit): XYFit {
-        val qowRuns = problem.getFeature<QowRuns>()?.runs ?: 2
-        val iterations = problem.getFeature<OptimizationIterations>()?.maxIterations ?: 50
+        val qowRuns = problem.attributes[QowRuns] ?: 2
+        val iterations = problem.attributes[OptimizationIterations] ?: 50
 
-        val freeParameters: Map<Symbol, Double> = problem.getFeature<OptimizationParameters>()?.let { op ->
-            problem.startPoint.filterKeys { it in op.symbols }
+        val freeParameters: Map<Symbol, Double> = problem.attributes[OptimizationParameters]?.let { symbols ->
+            problem.startPoint.filterKeys { it in symbols }
         } ?: problem.startPoint
 
         var qow = QoWeight(problem, freeParameters)
@@ -270,7 +264,10 @@ public object QowOptimizer : Optimizer<Double, XYFit> {
             qow = QoWeight(problem, res.freeParameters)
             res = qow.newtonianRun(maxSteps = iterations)
         }
-        val covariance = res.covariance()
-        return res.problem.withFeature(OptimizationResult(res.freeParameters), OptimizationCovariance(covariance))
+
+        return res.problem.withAttributes {
+            result(res.freeParameters)
+            covariance(res.covariance())
+        }
     }
 }
\ No newline at end of file
diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt
index 9e5396491..44b7d17bd 100644
--- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt
+++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt
@@ -1,38 +1,42 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
-@file:OptIn(UnstableKMathAPI::class)
+@file:OptIn(UnstableKMathAPI::class, UnstableKMathAPI::class)
 
 package space.kscience.kmath.optimization
 
+import space.kscience.attributes.*
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.data.XYColumnarData
 import space.kscience.kmath.data.indices
 import space.kscience.kmath.expressions.*
-import space.kscience.kmath.misc.FeatureSet
 import space.kscience.kmath.misc.Loggable
+import space.kscience.kmath.operations.DoubleField
 import space.kscience.kmath.operations.ExtendedField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.bindSymbol
 import kotlin.math.pow
 
 /**
  * Specify the way to compute distance from point to the curve as DifferentiableExpression
  */
-public interface PointToCurveDistance : OptimizationFeature {
+public interface PointToCurveDistance {
     public fun distance(problem: XYFit, index: Int): DifferentiableExpression<Double>
 
-    public companion object {
+    public companion object : OptimizationAttribute<PointToCurveDistance> {
         public val byY: PointToCurveDistance = object : PointToCurveDistance {
             override fun distance(problem: XYFit, index: Int): DifferentiableExpression<Double> {
                 val x = problem.data.x[index]
                 val y = problem.data.y[index]
 
                 return object : DifferentiableExpression<Double> {
+                    override val type: SafeType<Double> get() = DoubleField.type
+
                     override fun derivativeOrNull(
                         symbols: List<Symbol>,
                     ): Expression<Double>? = problem.model.derivativeOrNull(symbols)?.let { derivExpression ->
-                        Expression { arguments ->
+                        Expression(DoubleField.type) { arguments ->
                             derivExpression.invoke(arguments + (Symbol.x to x))
                         }
                     }
@@ -51,18 +55,21 @@ public interface PointToCurveDistance : OptimizationFeature {
  * Compute a wight of the point. The more the weight, the more impact this point will have on the fit.
  * By default, uses Dispersion^-1
  */
-public interface PointWeight : OptimizationFeature {
+public interface PointWeight {
     public fun weight(problem: XYFit, index: Int): DifferentiableExpression<Double>
 
-    public companion object {
+    public companion object : OptimizationAttribute<PointWeight> {
         public fun bySigma(sigmaSymbol: Symbol): PointWeight = object : PointWeight {
             override fun weight(problem: XYFit, index: Int): DifferentiableExpression<Double> =
                 object : DifferentiableExpression<Double> {
+                    override val type: SafeType<Double> get() = DoubleField.type
+
                     override fun invoke(arguments: Map<Symbol, Double>): Double {
                         return problem.data[sigmaSymbol]?.get(index)?.pow(-2) ?: 1.0
                     }
 
-                    override fun derivativeOrNull(symbols: List<Symbol>): Expression<Double> = Expression { 0.0 }
+                    override fun derivativeOrNull(symbols: List<Symbol>): Expression<Double> =
+                        Expression(DoubleField.type) { 0.0 }
                 }
 
             override fun toString(): String = "PointWeightBySigma($sigmaSymbol)"
@@ -79,41 +86,52 @@ public interface PointWeight : OptimizationFeature {
 public class XYFit(
     public val data: XYColumnarData<Double, Double, Double>,
     public val model: DifferentiableExpression<Double>,
-    override val features: FeatureSet<OptimizationFeature>,
+    override val attributes: Attributes,
     internal val pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY,
     internal val pointWeight: PointWeight = PointWeight.byYSigma,
     public val xSymbol: Symbol = Symbol.x,
 ) : OptimizationProblem<Double> {
+
+    override val type: SafeType<Double> get() = Float64Field.type
+
     public fun distance(index: Int): DifferentiableExpression<Double> = pointToCurveDistance.distance(this, index)
 
     public fun weight(index: Int): DifferentiableExpression<Double> = pointWeight.weight(this, index)
 }
 
-public fun XYFit.withFeature(vararg features: OptimizationFeature): XYFit {
-    return XYFit(data, model, this.features.with(*features), pointToCurveDistance, pointWeight)
-}
+
+public fun XYOptimization(
+    data: XYColumnarData<Double, Double, Double>,
+    model: DifferentiableExpression<Double>,
+    builder: AttributesBuilder<XYFit>.() -> Unit,
+): XYFit = XYFit(data, model, Attributes(builder))
+
+public fun XYFit.withAttributes(
+    modifier: AttributesBuilder<XYFit>.() -> Unit,
+): XYFit = XYFit(data, model, attributes.modified(modifier), pointToCurveDistance, pointWeight, xSymbol)
 
 public suspend fun XYColumnarData<Double, Double, Double>.fitWith(
     optimizer: Optimizer<Double, XYFit>,
     modelExpression: DifferentiableExpression<Double>,
     startingPoint: Map<Symbol, Double>,
-    vararg features: OptimizationFeature = emptyArray(),
+    attributes: Attributes = Attributes.EMPTY,
     xSymbol: Symbol = Symbol.x,
     pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY,
     pointWeight: PointWeight = PointWeight.byYSigma,
 ): XYFit {
-    var actualFeatures = FeatureSet.of(*features, OptimizationStartPoint(startingPoint))
 
-    if (actualFeatures.getFeature<OptimizationLog>() == null) {
-        actualFeatures = actualFeatures.with(OptimizationLog(Loggable.console))
-    }
     val problem = XYFit(
         this,
         modelExpression,
-        actualFeatures,
+        attributes.modified<XYFit> {
+            set(OptimizationStartPoint(), startingPoint)
+            if (!hasAny<OptimizationLog>()) {
+                set(OptimizationLog, Loggable.console)
+            }
+        },
         pointToCurveDistance,
         pointWeight,
-        xSymbol
+        xSymbol,
     )
     return optimizer.optimize(problem)
 }
@@ -125,7 +143,7 @@ public suspend fun <I : Any, A> XYColumnarData<Double, Double, Double>.fitWith(
     optimizer: Optimizer<Double, XYFit>,
     processor: AutoDiffProcessor<Double, I, A>,
     startingPoint: Map<Symbol, Double>,
-    vararg features: OptimizationFeature = emptyArray(),
+    attributes: Attributes = Attributes.EMPTY,
     xSymbol: Symbol = Symbol.x,
     pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY,
     pointWeight: PointWeight = PointWeight.byYSigma,
@@ -140,7 +158,7 @@ public suspend fun <I : Any, A> XYColumnarData<Double, Double, Double>.fitWith(
         optimizer = optimizer,
         modelExpression = modelExpression,
         startingPoint = startingPoint,
-        features = features,
+        attributes = attributes,
         xSymbol = xSymbol,
         pointToCurveDistance = pointToCurveDistance,
         pointWeight = pointWeight
@@ -152,7 +170,7 @@ public suspend fun <I : Any, A> XYColumnarData<Double, Double, Double>.fitWith(
  */
 public val XYFit.chiSquaredOrNull: Double?
     get() {
-        val result = startPoint + (resultPointOrNull ?: return null)
+        val result = startPoint + (resultOrNull ?: return null)
 
         return data.indices.sumOf { index ->
 
@@ -167,4 +185,4 @@ public val XYFit.chiSquaredOrNull: Double?
     }
 
 public val XYFit.dof: Int
-    get() = data.size - (getFeature<OptimizationParameters>()?.symbols?.size ?: startPoint.size)
\ No newline at end of file
+    get() = data.size - (attributes[OptimizationParameters]?.size ?: startPoint.size)
\ No newline at end of file
diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt
index 8ab9de48d..a3ccbfab4 100644
--- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt
+++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt
@@ -1,10 +1,12 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.optimization
 
+import space.kscience.attributes.AttributesBuilder
+import space.kscience.attributes.SafeType
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.data.XYColumnarData
 import space.kscience.kmath.data.indices
@@ -12,6 +14,7 @@ import space.kscience.kmath.expressions.DifferentiableExpression
 import space.kscience.kmath.expressions.Expression
 import space.kscience.kmath.expressions.Symbol
 import space.kscience.kmath.expressions.derivative
+import space.kscience.kmath.operations.Float64Field
 import kotlin.math.PI
 import kotlin.math.ln
 import kotlin.math.pow
@@ -22,7 +25,9 @@ private val oneOver2Pi = 1.0 / sqrt(2 * PI)
 
 @UnstableKMathAPI
 internal fun XYFit.logLikelihood(): DifferentiableExpression<Double> = object : DifferentiableExpression<Double> {
-    override fun derivativeOrNull(symbols: List<Symbol>): Expression<Double> = Expression { arguments ->
+    override val type: SafeType<Double> get() = Float64Field.type
+
+    override fun derivativeOrNull(symbols: List<Symbol>): Expression<Double> = Expression(type) { arguments ->
         data.indices.sumOf { index ->
             val d = distance(index)(arguments)
             val weight = weight(index)(arguments)
@@ -53,14 +58,18 @@ internal fun XYFit.logLikelihood(): DifferentiableExpression<Double> = object :
  */
 @UnstableKMathAPI
 public suspend fun Optimizer<Double, FunctionOptimization<Double>>.maximumLogLikelihood(problem: XYFit): XYFit {
-    val functionOptimization = FunctionOptimization(problem.features, problem.logLikelihood())
-    val result = optimize(functionOptimization.withFeatures(FunctionOptimizationTarget.MAXIMIZE))
-    return XYFit(problem.data, problem.model, result.features)
+    val functionOptimization = FunctionOptimization(problem.logLikelihood(), problem.attributes)
+    val result = optimize(
+        functionOptimization.withAttributes {
+            FunctionOptimizationTarget(OptimizationDirection.MAXIMIZE)
+        }
+    )
+    return XYFit(problem.data, problem.model, result.attributes)
 }
 
 @UnstableKMathAPI
 public suspend fun Optimizer<Double, FunctionOptimization<Double>>.maximumLogLikelihood(
     data: XYColumnarData<Double, Double, Double>,
     model: DifferentiableExpression<Double>,
-    builder: XYOptimizationBuilder.() -> Unit,
+    builder: AttributesBuilder<XYFit>.() -> Unit,
 ): XYFit = maximumLogLikelihood(XYOptimization(data, model, builder))
diff --git a/kmath-optimization/src/commonMain/tmp/QowFit.kt b/kmath-optimization/src/commonMain/tmp/QowFit.kt
index c78aef401..493ef8d12 100644
--- a/kmath-optimization/src/commonMain/tmp/QowFit.kt
+++ b/kmath-optimization/src/commonMain/tmp/QowFit.kt
@@ -319,10 +319,12 @@ public class QowFit(
      * generateErrors.
      */
     private fun generateErrors(): Matrix<Double> {
-        logger?.log { """
+        logger?.log {
+            """
             Starting errors estimation using quasioptimal weights method. The starting weight is:
                 ${curWeight.theta}
-             """.trimIndent()}
+             """.trimIndent()
+        }
         val curWeight = QoWeight(startingPoint)
 
         val covar = getCovariance(curWeight)
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/CombinedMinimumBuilder.kt b/kmath-optimization/src/commonMain/tmp/minuit/CombinedMinimumBuilder.kt
index 8c5452575..7cade49dc 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/CombinedMinimumBuilder.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/CombinedMinimumBuilder.kt
@@ -33,7 +33,7 @@ internal class CombinedMinimumBuilder : MinimumBuilder {
         seed: MinimumSeed?,
         strategy: MnStrategy?,
         maxfcn: Int,
-        toler: Double
+        toler: Double,
     ): FunctionMinimum {
         val min: FunctionMinimum = theVMMinimizer.minimize(fcn!!, gc, seed, strategy, maxfcn, toler)
         if (!min.isValid()) {
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/ContoursError.kt b/kmath-optimization/src/commonMain/tmp/minuit/ContoursError.kt
index 214d94c80..a9dcf652a 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/ContoursError.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/ContoursError.kt
@@ -28,7 +28,7 @@ class ContoursError internal constructor(
     points: List<Range>,
     xmnos: MinosError,
     ymnos: MinosError,
-    nfcn: Int
+    nfcn: Int,
 ) {
     private val theNFcn: Int
     private val thePoints: List<Range> = points
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/DavidonErrorUpdator.kt b/kmath-optimization/src/commonMain/tmp/minuit/DavidonErrorUpdator.kt
index 9eb2443e4..7fde0346c 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/DavidonErrorUpdator.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/DavidonErrorUpdator.kt
@@ -34,8 +34,10 @@ internal class DavidonErrorUpdator : MinimumErrorUpdator {
         var Vupd: MnAlgebraicSymMatrix =
             MnUtils.sub(MnUtils.div(MnUtils.outerProduct(dx), delgam), MnUtils.div(MnUtils.outerProduct(vg), gvg))
         if (delgam > gvg) {
-            Vupd = MnUtils.add(Vupd,
-                MnUtils.mul(MnUtils.outerProduct(MnUtils.sub(MnUtils.div(dx, delgam), MnUtils.div(vg, gvg))), gvg))
+            Vupd = MnUtils.add(
+                Vupd,
+                MnUtils.mul(MnUtils.outerProduct(MnUtils.sub(MnUtils.div(dx, delgam), MnUtils.div(vg, gvg))), gvg)
+            )
         }
         val sum_upd: Double = MnUtils.absoluteSumOfElements(Vupd)
         Vupd = MnUtils.add(Vupd, V0)
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/FunctionMinimum.kt b/kmath-optimization/src/commonMain/tmp/minuit/FunctionMinimum.kt
index e43523291..5ffc72e43 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/FunctionMinimum.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/FunctionMinimum.kt
@@ -46,11 +46,15 @@ class FunctionMinimum {
     internal constructor(seed: MinimumSeed, up: Double) {
         theSeed = seed
         theStates = ArrayList()
-        theStates.add(MinimumState(seed.parameters(),
-            seed.error(),
-            seed.gradient(),
-            seed.parameters().fval(),
-            seed.nfcn()))
+        theStates.add(
+            MinimumState(
+                seed.parameters(),
+                seed.error(),
+                seed.gradient(),
+                seed.parameters().fval(),
+                seed.nfcn()
+            )
+        )
         theErrorDef = up
         theUserState = MnUserParameterState()
     }
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MINUITFitter.kt b/kmath-optimization/src/commonMain/tmp/minuit/MINUITFitter.kt
index a26321249..3838fa8af 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/MINUITFitter.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/MINUITFitter.kt
@@ -97,6 +97,7 @@ class MINUITFitter : Fitter {
         when (method) {
             MINUIT_MINOS, MINUIT_MINIMIZE -> minuit =
                 MnMinimize(fcn, MINUITUtils.getFitParameters(pars, fitPars), strategy)
+
             MINUIT_SIMPLEX -> minuit = MnSimplex(fcn, MINUITUtils.getFitParameters(pars, fitPars), strategy)
             else -> minuit = MnMigrad(fcn, MINUITUtils.getFitParameters(pars, fitPars), strategy)
         }
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MINUITPlugin.kt b/kmath-optimization/src/commonMain/tmp/minuit/MINUITPlugin.kt
index 7eaefd9d2..4fc5822ce 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/MINUITPlugin.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/MINUITPlugin.kt
@@ -13,10 +13,12 @@ import hep.dataforge.context.*
  * @author Darksnake
  * @version $Id: $Id
  */
-@PluginDef(group = "hep.dataforge",
+@PluginDef(
+    group = "hep.dataforge",
     name = "MINUIT",
     dependsOn = ["hep.dataforge:fitting"],
-    info = "The MINUIT fitter engine for DataForge fitting")
+    info = "The MINUIT fitter engine for DataForge fitting"
+)
 class MINUITPlugin : BasicPlugin() {
     fun attach(@NotNull context: Context?) {
         super.attach(context)
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MinimumBuilder.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumBuilder.kt
index 7d918c339..8876c9575 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/MinimumBuilder.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/MinimumBuilder.kt
@@ -40,6 +40,6 @@ interface MinimumBuilder {
         seed: MinimumSeed?,
         strategy: MnStrategy?,
         maxfcn: Int,
-        toler: Double
+        toler: Double,
     ): FunctionMinimum
 }
\ No newline at end of file
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MinuitParameter.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinuitParameter.kt
index ff6834df4..e1eb972d9 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/MinuitParameter.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/MinuitParameter.kt
@@ -38,9 +38,9 @@ class MinuitParameter {
      * @param name a [String] object.
      * @param val a double.
      */
-    constructor(num: Int, name: String, `val`: Double) {
+    constructor(num: Int, name: String, value: Double) {
         theNum = num
-        theValue = `val`
+        theValue = value
         theConst = true
         theName = name
     }
@@ -53,9 +53,9 @@ class MinuitParameter {
      * @param val a double.
      * @param err a double.
      */
-    constructor(num: Int, name: String, `val`: Double, err: Double) {
+    constructor(num: Int, name: String, value: Double, err: Double) {
         theNum = num
-        theValue = `val`
+        theValue = value
         theError = err
         theName = name
     }
@@ -70,9 +70,9 @@ class MinuitParameter {
      * @param min a double.
      * @param max a double.
      */
-    constructor(num: Int, name: String, `val`: Double, err: Double, min: Double, max: Double) {
+    constructor(num: Int, name: String, value: Double, err: Double, min: Double, max: Double) {
         theNum = num
-        theValue = `val`
+        theValue = value
         theError = err
         theLoLimit = min
         theUpLimit = max
@@ -288,8 +288,8 @@ class MinuitParameter {
      *
      * @param val a double.
      */
-    fun setValue(`val`: Double) {
-        theValue = `val`
+    fun setValue(value: Double) {
+        theValue = value
     }
 
     /**
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnApplication.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnApplication.kt
index 025eea4ae..18707980b 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/MnApplication.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/MnApplication.kt
@@ -77,8 +77,8 @@ abstract class MnApplication {
      * @param val a double.
      * @param name a [String] object.
      */
-    fun add(name: String, `val`: Double, err: Double) {
-        theState.add(name, `val`, err)
+    fun add(name: String, value: Double, err: Double) {
+        theState.add(name, value, err)
     }
 
     /**
@@ -90,8 +90,8 @@ abstract class MnApplication {
      * @param val a double.
      * @param err a double.
      */
-    fun add(name: String, `val`: Double, err: Double, low: Double, up: Double) {
-        theState.add(name, `val`, err, low, up)
+    fun add(name: String, value: Double, err: Double, low: Double, up: Double) {
+        theState.add(name, value, err, low, up)
     }
 
     /**
@@ -100,8 +100,8 @@ abstract class MnApplication {
      * @param name a [String] object.
      * @param val a double.
      */
-    fun add(name: String, `val`: Double) {
-        theState.add(name, `val`)
+    fun add(name: String, value: Double) {
+        theState.add(name, value)
     }
 
     /**
@@ -254,14 +254,16 @@ abstract class MnApplication {
         if (maxfcn == 0) {
             maxfcn = 200 + 100 * npar + 5 * npar * npar
         }
-        val min: FunctionMinimum = minimizer().minimize(theFCN,
+        val min: FunctionMinimum = minimizer().minimize(
+            theFCN,
             theState,
             theStrategy,
             maxfcn,
             toler,
             theErrorDef,
             useAnalyticalDerivatives,
-            checkAnalyticalDerivatives)
+            checkAnalyticalDerivatives
+        )
         theNumCall += min.nfcn()
         theState = min.userState()
         return min
@@ -469,8 +471,8 @@ abstract class MnApplication {
      * @param index a int.
      * @param val a double.
      */
-    fun setValue(index: Int, `val`: Double) {
-        theState.setValue(index, `val`)
+    fun setValue(index: Int, value: Double) {
+        theState.setValue(index, value)
     }
 
     /**
@@ -480,8 +482,8 @@ abstract class MnApplication {
      * @param name a [String] object.
      * @param val a double.
      */
-    fun setValue(name: String?, `val`: Double) {
-        theState.setValue(name, `val`)
+    fun setValue(name: String?, value: Double) {
+        theState.setValue(name, value)
     }
 
     /**
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnContours.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnContours.kt
index 1b700f4e2..39eda5877 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/MnContours.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/MnContours.kt
@@ -113,9 +113,11 @@ class MnContours(fcn: MultiFunction?, min: FunctionMinimum?, stra: MnStrategy?)
             return ContoursError(px, py, result, mex, mey, nfcn)
         }
         val ey: Range = mey.range()
-        val migrad = MnMigrad(theFCN,
+        val migrad = MnMigrad(
+            theFCN,
             theMinimum!!.userState().copy(),
-            MnStrategy(max(0, theStrategy!!.strategy() - 1)))
+            MnStrategy(max(0, theStrategy!!.strategy() - 1))
+        )
         migrad.fix(px)
         migrad.setValue(px, valx + ex.getSecond())
         val exy_up: FunctionMinimum = migrad.minimize()
@@ -131,9 +133,11 @@ class MnContours(fcn: MultiFunction?, min: FunctionMinimum?, stra: MnStrategy?)
             MINUITPlugin.logStatic("MnContours is unable to find lower y value for x parameter $px.")
             return ContoursError(px, py, result, mex, mey, nfcn)
         }
-        val migrad1 = MnMigrad(theFCN,
+        val migrad1 = MnMigrad(
+            theFCN,
             theMinimum!!.userState().copy(),
-            MnStrategy(max(0, theStrategy!!.strategy() - 1)))
+            MnStrategy(max(0, theStrategy!!.strategy() - 1))
+        )
         migrad1.fix(py)
         migrad1.setValue(py, valy + ey.getSecond())
         val eyx_up: FunctionMinimum = migrad1.minimize()
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnFunctionCross.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnFunctionCross.kt
index a05590e53..da1bed482 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/MnFunctionCross.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/MnFunctionCross.kt
@@ -28,7 +28,7 @@ internal class MnFunctionCross(
     state: MnUserParameterState,
     fval: Double,
     stra: MnStrategy?,
-    errorDef: Double
+    errorDef: Double,
 ) {
     private val theErrorDef: Double
     private val theFCN: MultiFunction?
@@ -249,10 +249,13 @@ internal class MnFunctionCross(
             }
         }
         do {
-            val parbol: MnParabola = MnParabolaFactory.create(MnParabolaPoint(alsb[0], flsb[0]),
+            val parbol: MnParabola = MnParabolaFactory.create(
+                MnParabolaPoint(alsb[0], flsb[0]),
                 MnParabolaPoint(alsb[1], flsb[1]),
                 MnParabolaPoint(
-                    alsb[2], flsb[2]))
+                    alsb[2], flsb[2]
+                )
+            )
             val coeff1: Double = parbol.c()
             val coeff2: Double = parbol.b()
             val coeff3: Double = parbol.a()
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnHesse.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnHesse.kt
index 3bb6c4551..998324ad8 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/MnHesse.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/MnHesse.kt
@@ -161,7 +161,7 @@ class MnHesse {
         fcn: MultiFunction?,
         par: MnUserParameters,
         cov: MnUserCovariance,
-        maxcalls: Int
+        maxcalls: Int,
     ): MnUserParameterState {
         return calculate(fcn, MnUserParameterState(par, cov), maxcalls)
     }
@@ -186,10 +186,12 @@ class MnHesse {
         val gc = Numerical2PGradientCalculator(mfcn, state.getTransformation(), theStrategy)
         val par = MinimumParameters(x, amin)
         val gra: FunctionGradient = gc.gradient(par)
-        val tmp: MinimumState = calculate(mfcn,
+        val tmp: MinimumState = calculate(
+            mfcn,
             MinimumState(par, MinimumError(MnAlgebraicSymMatrix(n), 1.0), gra, state.edm(), state.nfcn()),
             state.getTransformation(),
-            maxcalls)
+            maxcalls
+        )
         return MnUserParameterState(tmp, errDef, state.getTransformation())
     }
 
@@ -326,11 +328,13 @@ class MnHesse {
                 MINUITPlugin.logStatic("MnHesse: matrix is invalid!")
                 MINUITPlugin.logStatic("MnHesse: matrix is not pos. def.!")
                 MINUITPlugin.logStatic("MnHesse: matrix was forced pos. def.")
-                return MinimumState(st.parameters(),
+                return MinimumState(
+                    st.parameters(),
                     MinimumError(vhmat, MnMadePosDef()),
                     gr,
                     st.edm(),
-                    mfcn.numOfCalls())
+                    mfcn.numOfCalls()
+                )
             }
 
             //calculate edm
@@ -346,11 +350,13 @@ class MnHesse {
                 vhmat[j, j] = if (tmp < prec.eps2()) 1.0 else tmp
                 j++
             }
-            MinimumState(st.parameters(),
+            MinimumState(
+                st.parameters(),
                 MinimumError(vhmat, MnHesseFailed()),
                 st.gradient(),
                 st.edm(),
-                st.nfcn() + mfcn.numOfCalls())
+                st.nfcn() + mfcn.numOfCalls()
+            )
         }
     }
 
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnLineSearch.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnLineSearch.kt
index 7b1171d3c..6d42ad6ac 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/MnLineSearch.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/MnLineSearch.kt
@@ -28,7 +28,7 @@ internal object MnLineSearch {
         st: MinimumParameters,
         step: RealVector,
         gdel: Double,
-        prec: MnMachinePrecision
+        prec: MnMachinePrecision,
     ): MnParabolaPoint {
         var overal = 1000.0
         var undral = -100.0
@@ -154,7 +154,8 @@ internal object MnLineSearch {
                 val toler9: Double = max(toler8, abs(toler8 * slam))
                 // min. of parabola at one point
                 if (abs(p0.x() - slam) < toler9 || abs(p1.x() - slam) < toler9 || abs(
-                        p2.x() - slam) < toler9
+                        p2.x() - slam
+                    ) < toler9
                 ) {
                     return MnParabolaPoint(xvmin, fvmin)
                 }
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnMigrad.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnMigrad.kt
index 22616a1a6..2c0b85561 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/MnMigrad.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/MnMigrad.kt
@@ -58,9 +58,11 @@ class MnMigrad
      * @param fcn a [MultiFunction] object.
      * @param par an array of double.
      */
-    constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, stra: Int) : this(fcn,
+    constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, stra: Int) : this(
+        fcn,
         MnUserParameterState(par, err),
-        MnStrategy(stra))
+        MnStrategy(stra)
+    )
 
     /**
      * construct from MultiFunction + double[] for parameters and
@@ -81,9 +83,11 @@ class MnMigrad
      * @param fcn a [MultiFunction] object.
      * @param par an array of double.
      */
-    constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, stra: Int) : this(fcn,
+    constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, stra: Int) : this(
+        fcn,
         MnUserParameterState(par, cov),
-        MnStrategy(stra))
+        MnStrategy(stra)
+    )
 
     /**
      * construct from MultiFunction + MnUserParameters with default
@@ -101,9 +105,11 @@ class MnMigrad
      * @param par a [hep.dataforge.MINUIT.MnUserParameters] object.
      * @param fcn a [MultiFunction] object.
      */
-    constructor(fcn: MultiFunction?, par: MnUserParameters, stra: Int) : this(fcn,
+    constructor(fcn: MultiFunction?, par: MnUserParameters, stra: Int) : this(
+        fcn,
         MnUserParameterState(par),
-        MnStrategy(stra))
+        MnStrategy(stra)
+    )
 
     /**
      * construct from MultiFunction + MnUserParameters + MnUserCovariance
@@ -113,10 +119,12 @@ class MnMigrad
      * @param par a [hep.dataforge.MINUIT.MnUserParameters] object.
      * @param fcn a [MultiFunction] object.
      */
-    constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance) : this(fcn,
+    constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance) : this(
+        fcn,
         par,
         cov,
-        DEFAULT_STRATEGY)
+        DEFAULT_STRATEGY
+    )
 
     /**
      * construct from MultiFunction + MnUserParameters + MnUserCovariance
@@ -126,9 +134,11 @@ class MnMigrad
      * @param fcn a [MultiFunction] object.
      * @param par a [hep.dataforge.MINUIT.MnUserParameters] object.
      */
-    constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance, stra: Int) : this(fcn,
+    constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance, stra: Int) : this(
+        fcn,
         MnUserParameterState(par, cov),
-        MnStrategy(stra))
+        MnStrategy(stra)
+    )
 
     override fun minimizer(): ModularFunctionMinimizer {
         return theMinimizer
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnMinimize.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnMinimize.kt
index ea14a5453..dfafebba8 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/MnMinimize.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/MnMinimize.kt
@@ -55,9 +55,11 @@ class MnMinimize
      * @param fcn a [MultiFunction] object.
      * @param par an array of double.
      */
-    constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, stra: Int) : this(fcn,
+    constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, stra: Int) : this(
+        fcn,
         MnUserParameterState(par, err),
-        MnStrategy(stra))
+        MnStrategy(stra)
+    )
 
     /**
      * construct from MultiFunction + double[] for parameters and
@@ -78,9 +80,11 @@ class MnMinimize
      * @param fcn a [MultiFunction] object.
      * @param par an array of double.
      */
-    constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, stra: Int) : this(fcn,
+    constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, stra: Int) : this(
+        fcn,
         MnUserParameterState(par, cov),
-        MnStrategy(stra))
+        MnStrategy(stra)
+    )
 
     /**
      * construct from MultiFunction + MnUserParameters with default
@@ -98,9 +102,11 @@ class MnMinimize
      * @param par a [hep.dataforge.MINUIT.MnUserParameters] object.
      * @param fcn a [MultiFunction] object.
      */
-    constructor(fcn: MultiFunction?, par: MnUserParameters, stra: Int) : this(fcn,
+    constructor(fcn: MultiFunction?, par: MnUserParameters, stra: Int) : this(
+        fcn,
         MnUserParameterState(par),
-        MnStrategy(stra))
+        MnStrategy(stra)
+    )
 
     /**
      * construct from MultiFunction + MnUserParameters + MnUserCovariance
@@ -110,10 +116,12 @@ class MnMinimize
      * @param par a [hep.dataforge.MINUIT.MnUserParameters] object.
      * @param fcn a [MultiFunction] object.
      */
-    constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance) : this(fcn,
+    constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance) : this(
+        fcn,
         par,
         cov,
-        DEFAULT_STRATEGY)
+        DEFAULT_STRATEGY
+    )
 
     /**
      * construct from MultiFunction + MnUserParameters + MnUserCovariance
@@ -123,9 +131,11 @@ class MnMinimize
      * @param fcn a [MultiFunction] object.
      * @param par a [hep.dataforge.MINUIT.MnUserParameters] object.
      */
-    constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance, stra: Int) : this(fcn,
+    constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance, stra: Int) : this(
+        fcn,
         MnUserParameterState(par, cov),
-        MnStrategy(stra))
+        MnStrategy(stra)
+    )
 
     override fun minimizer(): ModularFunctionMinimizer {
         return theMinimizer
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnMinos.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnMinos.kt
index d49379b3b..05499bd93 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/MnMinos.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/MnMinos.kt
@@ -106,8 +106,8 @@ class MnMinos(fcn: MultiFunction?, min: FunctionMinimum?, stra: MnStrategy?) {
         val para = intArrayOf(par)
         val upar: MnUserParameterState = theMinimum!!.userState().copy()
         val err: Double = upar.error(par)
-        val `val`: Double = upar.value(par) - err
-        val xmid = doubleArrayOf(`val`)
+        val value: Double = upar.value(par) - err
+        val xmid = doubleArrayOf(value)
         val xdir = doubleArrayOf(-err)
         val ind: Int = upar.intOfExt(par)
         val m: MnAlgebraicSymMatrix = theMinimum!!.error().matrix()
@@ -121,7 +121,7 @@ class MnMinos(fcn: MultiFunction?, min: FunctionMinimum?, stra: MnStrategy?) {
             upar.setValue(ext, upar.value(ext) - xdev)
         }
         upar.fix(par)
-        upar.setValue(par, `val`)
+        upar.setValue(par, value)
         val toler = 0.1
         val cross = MnFunctionCross(theFCN, upar, theMinimum!!.fval(), theStrategy, errDef)
         val aopt: MnCross = cross.cross(para, xmid, xdir, toler, maxcalls)
@@ -330,8 +330,8 @@ class MnMinos(fcn: MultiFunction?, min: FunctionMinimum?, stra: MnStrategy?) {
         val para = intArrayOf(par)
         val upar: MnUserParameterState = theMinimum!!.userState().copy()
         val err: Double = upar.error(par)
-        val `val`: Double = upar.value(par) + err
-        val xmid = doubleArrayOf(`val`)
+        val value: Double = upar.value(par) + err
+        val xmid = doubleArrayOf(value)
         val xdir = doubleArrayOf(err)
         val ind: Int = upar.intOfExt(par)
         val m: MnAlgebraicSymMatrix = theMinimum!!.error().matrix()
@@ -345,7 +345,7 @@ class MnMinos(fcn: MultiFunction?, min: FunctionMinimum?, stra: MnStrategy?) {
             upar.setValue(ext, upar.value(ext) + xdev)
         }
         upar.fix(par)
-        upar.setValue(par, `val`)
+        upar.setValue(par, value)
         val toler = 0.1
         val cross = MnFunctionCross(theFCN, upar, theMinimum!!.fval(), theStrategy, errDef)
         val aopt: MnCross = cross.cross(para, xmid, xdir, toler, maxcalls)
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnPrint.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnPrint.kt
index ce018c2a4..6c888f1d0 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/MnPrint.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/MnPrint.kt
@@ -294,12 +294,14 @@ object MnPrint {
             os.println(me.upperState())
         }
         os.println("# ext. ||   name    || value@min ||  negative || positive  ")
-        os.printf("%4d||%10s||%10g||%10g||%10g\n",
+        os.printf(
+            "%4d||%10s||%10g||%10g||%10g\n",
             me.parameter(),
             me.lowerState().name(me.parameter()),
             me.min(),
             me.lower(),
-            me.upper())
+            me.upper()
+        )
         os.println()
     }
 
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnScan.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnScan.kt
index 63e565b4f..cd253778b 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/MnScan.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/MnScan.kt
@@ -51,9 +51,11 @@ class MnScan(fcn: MultiFunction?, par: MnUserParameterState, str: MnStrategy) :
      * @param fcn a [MultiFunction] object.
      * @param par an array of double.
      */
-    constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, stra: Int) : this(fcn,
+    constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, stra: Int) : this(
+        fcn,
         MnUserParameterState(par, err),
-        MnStrategy(stra))
+        MnStrategy(stra)
+    )
 
     /**
      * construct from MultiFunction + double[] for parameters and
@@ -74,9 +76,11 @@ class MnScan(fcn: MultiFunction?, par: MnUserParameterState, str: MnStrategy) :
      * @param fcn a [MultiFunction] object.
      * @param par an array of double.
      */
-    constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, stra: Int) : this(fcn,
+    constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, stra: Int) : this(
+        fcn,
         MnUserParameterState(par, cov),
-        MnStrategy(stra))
+        MnStrategy(stra)
+    )
 
     /**
      * construct from MultiFunction + MnUserParameters with default
@@ -94,9 +98,11 @@ class MnScan(fcn: MultiFunction?, par: MnUserParameterState, str: MnStrategy) :
      * @param par a [hep.dataforge.MINUIT.MnUserParameters] object.
      * @param fcn a [MultiFunction] object.
      */
-    constructor(fcn: MultiFunction?, par: MnUserParameters, stra: Int) : this(fcn,
+    constructor(fcn: MultiFunction?, par: MnUserParameters, stra: Int) : this(
+        fcn,
         MnUserParameterState(par),
-        MnStrategy(stra))
+        MnStrategy(stra)
+    )
 
     /**
      * construct from MultiFunction + MnUserParameters + MnUserCovariance
@@ -106,10 +112,12 @@ class MnScan(fcn: MultiFunction?, par: MnUserParameterState, str: MnStrategy) :
      * @param par a [hep.dataforge.MINUIT.MnUserParameters] object.
      * @param fcn a [MultiFunction] object.
      */
-    constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance) : this(fcn,
+    constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance) : this(
+        fcn,
         par,
         cov,
-        DEFAULT_STRATEGY)
+        DEFAULT_STRATEGY
+    )
 
     /**
      * construct from MultiFunction + MnUserParameters + MnUserCovariance
@@ -119,9 +127,11 @@ class MnScan(fcn: MultiFunction?, par: MnUserParameterState, str: MnStrategy) :
      * @param fcn a [MultiFunction] object.
      * @param par a [hep.dataforge.MINUIT.MnUserParameters] object.
      */
-    constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance, stra: Int) : this(fcn,
+    constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance, stra: Int) : this(
+        fcn,
         MnUserParameterState(par, cov),
-        MnStrategy(stra))
+        MnStrategy(stra)
+    )
 
     override fun minimizer(): ModularFunctionMinimizer {
         return theMinimizer
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnSeedGenerator.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnSeedGenerator.kt
index a42edf4f1..8bc038f16 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/MnSeedGenerator.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/MnSeedGenerator.kt
@@ -51,16 +51,10 @@ internal class MnSeedGenerator : MinimumSeedGenerator {
                     val calculated: Double = hgrd.getFirst().getGradient().getEntry(i)
                     val delta: Double = hgrd.getSecond().getEntry(i)
                     if (abs(calculated - provided) > delta) {
-                        MINUITPlugin.logStatic(""
-                                + "gradient discrepancy of external parameter \"%d\" "
-                                + "(internal parameter \"%d\") too large. Expected: \"%f\", provided: \"%f\"",
-                            st.getTransformation().extOfInt(i), i, provided, calculated)
-
-//                        
-//                        MINUITPlugin.logStatic("gradient discrepancy of external parameter "
-//                                + st.getTransformation().extOfInt(i) 
-//                                + " (internal parameter " + i + ") too large.");
-//                        good = false;
+                        MINUITPlugin.logStatic(
+                            """gradient discrepancy of external parameter "%d" (internal parameter "%d") too large. Expected: "%f", provided: "%f"""",
+                            st.getTransformation().extOfInt(i), i, provided, calculated
+                        )
                     }
                 }
                 if (!good) {
@@ -82,8 +76,7 @@ internal class MnSeedGenerator : MinimumSeedGenerator {
             dcovar = 0.0
         } else {
             for (i in 0 until n) {
-                mat[i, i] = if (abs(dgrad.getGradientDerivative()
-                        .getEntry(i)) > prec.eps2()
+                mat[i, i] = if (abs(dgrad.getGradientDerivative().getEntry(i)) > prec.eps2()
                 ) 1.0 / dgrad.getGradientDerivative().getEntry(i) else 1.0
             }
         }
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnSimplex.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnSimplex.kt
index b00745f26..ef617f0a1 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/MnSimplex.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/MnSimplex.kt
@@ -59,9 +59,11 @@ class MnSimplex
      * @param fcn a [MultiFunction] object.
      * @param par an array of double.
      */
-    constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, stra: Int) : this(fcn,
+    constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, stra: Int) : this(
+        fcn,
         MnUserParameterState(par, err),
-        MnStrategy(stra))
+        MnStrategy(stra)
+    )
 
     /**
      * construct from MultiFunction + double[] for parameters and
@@ -82,9 +84,11 @@ class MnSimplex
      * @param fcn a [MultiFunction] object.
      * @param par an array of double.
      */
-    constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, stra: Int) : this(fcn,
+    constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, stra: Int) : this(
+        fcn,
         MnUserParameterState(par, cov),
-        MnStrategy(stra))
+        MnStrategy(stra)
+    )
 
     /**
      * construct from MultiFunction + MnUserParameters with default
@@ -102,9 +106,11 @@ class MnSimplex
      * @param par a [hep.dataforge.MINUIT.MnUserParameters] object.
      * @param fcn a [MultiFunction] object.
      */
-    constructor(fcn: MultiFunction?, par: MnUserParameters, stra: Int) : this(fcn,
+    constructor(fcn: MultiFunction?, par: MnUserParameters, stra: Int) : this(
+        fcn,
         MnUserParameterState(par),
-        MnStrategy(stra))
+        MnStrategy(stra)
+    )
 
     /**
      * construct from MultiFunction + MnUserParameters + MnUserCovariance
@@ -114,10 +120,12 @@ class MnSimplex
      * @param par a [hep.dataforge.MINUIT.MnUserParameters] object.
      * @param fcn a [MultiFunction] object.
      */
-    constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance) : this(fcn,
+    constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance) : this(
+        fcn,
         par,
         cov,
-        DEFAULT_STRATEGY)
+        DEFAULT_STRATEGY
+    )
 
     /**
      * construct from MultiFunction + MnUserParameters + MnUserCovariance
@@ -127,9 +135,11 @@ class MnSimplex
      * @param fcn a [MultiFunction] object.
      * @param par a [hep.dataforge.MINUIT.MnUserParameters] object.
      */
-    constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance, stra: Int) : this(fcn,
+    constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance, stra: Int) : this(
+        fcn,
         MnUserParameterState(par, cov),
-        MnStrategy(stra))
+        MnStrategy(stra)
+    )
 
     /** {@inheritDoc}  */
     override fun minimizer(): ModularFunctionMinimizer {
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameterState.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameterState.kt
index e80dd60a1..8b2f8786e 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameterState.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameterState.kt
@@ -194,10 +194,14 @@ class MnUserParameterState {
                 fix(ipar.name())
             } else if (ipar.hasLimits()) {
                 val i: Int = trafo.intOfExt(ipar.number())
-                val err: Double = if (st.hasCovariance()) sqrt(2.0 * up * st.error().invHessian()[i, i]) else st.parameters().dirin().getEntry(i)
-                add(ipar.name(),
+                val err: Double =
+                    if (st.hasCovariance()) sqrt(2.0 * up * st.error().invHessian()[i, i]) else st.parameters().dirin()
+                        .getEntry(i)
+                add(
+                    ipar.name(),
                     trafo.int2ext(i, st.vec().getEntry(i)),
-                    trafo.int2extError(i, st.vec().getEntry(i), err))
+                    trafo.int2extError(i, st.vec().getEntry(i), err)
+                )
                 if (ipar.hasLowerLimit() && ipar.hasUpperLimit()) {
                     setLimits(ipar.name(), ipar.lowerLimit(), ipar.upperLimit())
                 } else if (ipar.hasLowerLimit() && !ipar.hasUpperLimit()) {
@@ -207,7 +211,9 @@ class MnUserParameterState {
                 }
             } else {
                 val i: Int = trafo.intOfExt(ipar.number())
-                val err: Double = if (st.hasCovariance()) sqrt(2.0 * up * st.error().invHessian()[i, i]) else st.parameters().dirin().getEntry(i)
+                val err: Double =
+                    if (st.hasCovariance()) sqrt(2.0 * up * st.error().invHessian()[i, i]) else st.parameters().dirin()
+                        .getEntry(i)
                 add(ipar.name(), st.vec().getEntry(i), err)
             }
         }
@@ -229,9 +235,9 @@ class MnUserParameterState {
      * @param val a double.
      * @param name a [String] object.
      */
-    fun add(name: String, `val`: Double, err: Double) {
-        theParameters.add(name, `val`, err)
-        theIntParameters.add(`val`)
+    fun add(name: String, value: Double, err: Double) {
+        theParameters.add(name, value, err)
+        theIntParameters.add(value)
         theCovarianceValid = false
         theGCCValid = false
         theValid = true
@@ -246,10 +252,10 @@ class MnUserParameterState {
      * @param err a double.
      * @param up a double.
      */
-    fun add(name: String, `val`: Double, err: Double, low: Double, up: Double) {
-        theParameters.add(name, `val`, err, low, up)
+    fun add(name: String, value: Double, err: Double, low: Double, up: Double) {
+        theParameters.add(name, value, err, low, up)
         theCovarianceValid = false
-        theIntParameters.add(ext2int(index(name), `val`))
+        theIntParameters.add(ext2int(index(name), value))
         theGCCValid = false
         theValid = true
     }
@@ -260,8 +266,8 @@ class MnUserParameterState {
      * @param name a [String] object.
      * @param val a double.
      */
-    fun add(name: String, `val`: Double) {
-        theParameters.add(name, `val`)
+    fun add(name: String, value: Double) {
+        theParameters.add(name, value)
         theValid = true
     }
 
@@ -325,8 +331,8 @@ class MnUserParameterState {
         return theParameters.errors()
     }
 
-    fun ext2int(i: Int, `val`: Double): Double {
-        return theParameters.trafo().ext2int(i, `val`)
+    fun ext2int(i: Int, value: Double): Double {
+        return theParameters.trafo().ext2int(i, value)
     }
 
     /**
@@ -420,8 +426,8 @@ class MnUserParameterState {
     }
 
     // transformation internal <-> external
-    fun int2ext(i: Int, `val`: Double): Double {
-        return theParameters.trafo().int2ext(i, `val`)
+    fun int2ext(i: Int, value: Double): Double {
+        return theParameters.trafo().int2ext(i, value)
     }
 
     fun intCovariance(): MnUserCovariance {
@@ -694,14 +700,14 @@ class MnUserParameterState {
      * @param e a int.
      * @param val a double.
      */
-    fun setValue(e: Int, `val`: Double) {
-        theParameters.setValue(e, `val`)
+    fun setValue(e: Int, value: Double) {
+        theParameters.setValue(e, value)
         if (!parameter(e).isFixed() && !parameter(e).isConst()) {
             val i = intOfExt(e)
             if (parameter(e).hasLimits()) {
-                theIntParameters[i] = ext2int(e, `val`)
+                theIntParameters[i] = ext2int(e, value)
             } else {
-                theIntParameters[i] = `val`
+                theIntParameters[i] = value
             }
         }
     }
@@ -713,8 +719,8 @@ class MnUserParameterState {
      * @param name a [String] object.
      * @param val a double.
      */
-    fun setValue(name: String?, `val`: Double) {
-        setValue(index(name), `val`)
+    fun setValue(name: String?, value: Double) {
+        setValue(index(name), value)
     }
 
     /** {@inheritDoc}  */
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameters.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameters.kt
index 9bac54b25..bdbefb4d1 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameters.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameters.kt
@@ -65,8 +65,8 @@ class MnUserParameters {
      * @param val a double.
      * @param name a [String] object.
      */
-    fun add(name: String, `val`: Double, err: Double) {
-        theTransformation.add(name, `val`, err)
+    fun add(name: String, value: Double, err: Double) {
+        theTransformation.add(name, value, err)
     }
 
     /**
@@ -78,8 +78,8 @@ class MnUserParameters {
      * @param val a double.
      * @param err a double.
      */
-    fun add(name: String, `val`: Double, err: Double, low: Double, up: Double) {
-        theTransformation.add(name, `val`, err, low, up)
+    fun add(name: String, value: Double, err: Double, low: Double, up: Double) {
+        theTransformation.add(name, value, err, low, up)
     }
 
     /**
@@ -88,8 +88,8 @@ class MnUserParameters {
      * @param name a [String] object.
      * @param val a double.
      */
-    fun add(name: String, `val`: Double) {
-        theTransformation.add(name, `val`)
+    fun add(name: String, value: Double) {
+        theTransformation.add(name, value)
     }
 
     /**
@@ -344,8 +344,8 @@ class MnUserParameters {
      * @param index a int.
      * @param val a double.
      */
-    fun setValue(index: Int, `val`: Double) {
-        theTransformation.setValue(index, `val`)
+    fun setValue(index: Int, value: Double) {
+        theTransformation.setValue(index, value)
     }
 
     /**
@@ -355,8 +355,8 @@ class MnUserParameters {
      * @param name a [String] object.
      * @param val a double.
      */
-    fun setValue(name: String?, `val`: Double) {
-        theTransformation.setValue(name, `val`)
+    fun setValue(name: String?, value: Double) {
+        theTransformation.setValue(name, value)
     }
 
     /** {@inheritDoc}  */
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnUserTransformation.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUserTransformation.kt
index 1066ac2da..ca17611b1 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/MnUserTransformation.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/MnUserTransformation.kt
@@ -64,12 +64,12 @@ class MnUserTransformation {
      * @param err
      * @param val
      */
-    fun add(name: String, `val`: Double, err: Double) {
+    fun add(name: String, value: Double, err: Double) {
         require(!nameMap.containsKey(name)) { "duplicate name: $name" }
         nameMap[name] = theParameters.size
         theExtOfInt.add(theParameters.size)
-        theCache.add(`val`)
-        theParameters.add(MinuitParameter(theParameters.size, name, `val`, err))
+        theCache.add(value)
+        theParameters.add(MinuitParameter(theParameters.size, name, value, err))
     }
 
     /**
@@ -77,12 +77,12 @@ class MnUserTransformation {
      * @param up
      * @param low
      */
-    fun add(name: String, `val`: Double, err: Double, low: Double, up: Double) {
+    fun add(name: String, value: Double, err: Double, low: Double, up: Double) {
         require(!nameMap.containsKey(name)) { "duplicate name: $name" }
         nameMap[name] = theParameters.size
         theExtOfInt.add(theParameters.size)
-        theCache.add(`val`)
-        theParameters.add(MinuitParameter(theParameters.size, name, `val`, err, low, up))
+        theCache.add(value)
+        theParameters.add(MinuitParameter(theParameters.size, name, value, err, low, up))
     }
 
     /**
@@ -90,11 +90,11 @@ class MnUserTransformation {
      * @param name
      * @param val
      */
-    fun add(name: String, `val`: Double) {
+    fun add(name: String, value: Double) {
         require(!nameMap.containsKey(name)) { "duplicate name: $name" }
         nameMap[name] = theParameters.size
-        theCache.add(`val`)
-        theParameters.add(MinuitParameter(theParameters.size, name, `val`))
+        theCache.add(value)
+        theParameters.add(MinuitParameter(theParameters.size, name, value))
     }
 
     /**
@@ -107,18 +107,20 @@ class MnUserTransformation {
         return MnUserTransformation(this)
     }
 
-    fun dInt2Ext(i: Int, `val`: Double): Double {
+    fun dInt2Ext(i: Int, value: Double): Double {
         var dd = 1.0
         val parm: MinuitParameter = theParameters[theExtOfInt[i]]
         if (parm.hasLimits()) {
             dd = if (parm.hasUpperLimit() && parm.hasLowerLimit()) {
-                theDoubleLimTrafo.dInt2Ext(`val`,
+                theDoubleLimTrafo.dInt2Ext(
+                    value,
                     parm.upperLimit(),
-                    parm.lowerLimit())
+                    parm.lowerLimit()
+                )
             } else if (parm.hasUpperLimit() && !parm.hasLowerLimit()) {
-                theUpperLimTrafo.dInt2Ext(`val`, parm.upperLimit())
+                theUpperLimTrafo.dInt2Ext(value, parm.upperLimit())
             } else {
-                theLowerLimTrafo.dInt2Ext(`val`, parm.lowerLimit())
+                theLowerLimTrafo.dInt2Ext(value, parm.lowerLimit())
             }
         }
         return dd
@@ -141,24 +143,30 @@ class MnUserTransformation {
         return result
     }
 
-    fun ext2int(i: Int, `val`: Double): Double {
+    fun ext2int(i: Int, value: Double): Double {
         val parm: MinuitParameter = theParameters[i]
         return if (parm.hasLimits()) {
             if (parm.hasUpperLimit() && parm.hasLowerLimit()) {
-                theDoubleLimTrafo.ext2int(`val`,
+                theDoubleLimTrafo.ext2int(
+                    value,
                     parm.upperLimit(),
                     parm.lowerLimit(),
-                    precision())
+                    precision()
+                )
             } else if (parm.hasUpperLimit() && !parm.hasLowerLimit()) {
-                theUpperLimTrafo.ext2int(`val`,
+                theUpperLimTrafo.ext2int(
+                    value,
                     parm.upperLimit(),
-                    precision())
+                    precision()
+                )
             } else {
-                theLowerLimTrafo.ext2int(`val`,
+                theLowerLimTrafo.ext2int(
+                    value,
                     parm.lowerLimit(),
-                    precision())
+                    precision()
+                )
             }
-        } else `val`
+        } else value
     }
 
     fun extOfInt(internal: Int): Int {
@@ -192,19 +200,21 @@ class MnUserTransformation {
         return nameMap[name]!!
     }
 
-    fun int2ext(i: Int, `val`: Double): Double {
+    fun int2ext(i: Int, value: Double): Double {
         val parm: MinuitParameter = theParameters[theExtOfInt[i]]
         return if (parm.hasLimits()) {
             if (parm.hasUpperLimit() && parm.hasLowerLimit()) {
-                theDoubleLimTrafo.int2ext(`val`,
+                theDoubleLimTrafo.int2ext(
+                    value,
                     parm.upperLimit(),
-                    parm.lowerLimit())
+                    parm.lowerLimit()
+                )
             } else if (parm.hasUpperLimit() && !parm.hasLowerLimit()) {
-                theUpperLimTrafo.int2ext(`val`, parm.upperLimit())
+                theUpperLimTrafo.int2ext(value, parm.upperLimit())
             } else {
-                theLowerLimTrafo.int2ext(`val`, parm.lowerLimit())
+                theLowerLimTrafo.int2ext(value, parm.lowerLimit())
             }
-        } else `val`
+        } else value
     }
 
     fun int2extCovariance(vec: RealVector, cov: MnAlgebraicSymMatrix): MnUserCovariance {
@@ -225,13 +235,13 @@ class MnUserTransformation {
         return result
     }
 
-    fun int2extError(i: Int, `val`: Double, err: Double): Double {
+    fun int2extError(i: Int, value: Double, err: Double): Double {
         var dx = err
         val parm: MinuitParameter = theParameters[theExtOfInt[i]]
         if (parm.hasLimits()) {
-            val ui = int2ext(i, `val`)
-            var du1 = int2ext(i, `val` + dx) - ui
-            val du2 = int2ext(i, `val` - dx) - ui
+            val ui = int2ext(i, value)
+            var du1 = int2ext(i, value + dx) - ui
+            val du2 = int2ext(i, value - dx) - ui
             if (parm.hasUpperLimit() && parm.hasLowerLimit()) {
                 if (dx > 1.0) {
                     du1 = parm.upperLimit() - parm.lowerLimit()
@@ -344,13 +354,13 @@ class MnUserTransformation {
         setUpperLimit(index(name), up)
     }
 
-    fun setValue(index: Int, `val`: Double) {
-        theParameters[index].setValue(`val`)
-        theCache[index] = `val`
+    fun setValue(index: Int, value: Double) {
+        theParameters[index].setValue(value)
+        theCache[index] = value
     }
 
-    fun setValue(name: String?, `val`: Double) {
-        setValue(index(name), `val`)
+    fun setValue(name: String?, value: Double) {
+        setValue(index(name), value)
     }
 
     fun transform(pstates: RealVector): ArrayRealVector {
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/ModularFunctionMinimizer.kt b/kmath-optimization/src/commonMain/tmp/minuit/ModularFunctionMinimizer.kt
index 84130d24f..cb61e5b03 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/ModularFunctionMinimizer.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/ModularFunctionMinimizer.kt
@@ -33,7 +33,7 @@ abstract class ModularFunctionMinimizer {
         toler: Double,
         errorDef: Double,
         useAnalyticalGradient: Boolean,
-        checkGradient: Boolean
+        checkGradient: Boolean,
     ): FunctionMinimum {
         var maxfcn = maxfcn
         val mfcn = MnUserFcn(fcn, errorDef, st.getTransformation())
@@ -64,7 +64,7 @@ abstract class ModularFunctionMinimizer {
         seed: MinimumSeed?,
         strategy: MnStrategy?,
         maxfcn: Int,
-        toler: Double
+        toler: Double,
     ): FunctionMinimum {
         return builder().minimum(mfcn, gc, seed, strategy, maxfcn, toler * mfcn.errorDef())
     }
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/NegativeG2LineSearch.kt b/kmath-optimization/src/commonMain/tmp/minuit/NegativeG2LineSearch.kt
index 2e9ce5813..bc2b35234 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/NegativeG2LineSearch.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/NegativeG2LineSearch.kt
@@ -54,8 +54,10 @@ internal object NegativeG2LineSearch {
                     var step: RealVector = ArrayRealVector(n)
                     step.setEntry(i, dgrad.getStep().getEntry(i) * dgrad.getGradient().getEntry(i))
                     if (abs(dgrad.getGradient().getEntry(i)) > prec.eps2()) {
-                        step.setEntry(i,
-                            step.getEntry(i) * (-1.0 / abs(dgrad.getGradient().getEntry(i))))
+                        step.setEntry(
+                            i,
+                            step.getEntry(i) * (-1.0 / abs(dgrad.getGradient().getEntry(i)))
+                        )
                     }
                     val gdel: Double = step.getEntry(i) * dgrad.getGradient().getEntry(i)
                     val pp: MnParabolaPoint = MnLineSearch.search(fcn, pa, step, gdel, prec)
@@ -69,8 +71,7 @@ internal object NegativeG2LineSearch {
         } while (iter++ < 2 * n && iterate)
         val mat = MnAlgebraicSymMatrix(n)
         for (i in 0 until n) {
-            mat[i, i] = if (abs(dgrad.getGradientDerivative()
-                    .getEntry(i)) > prec.eps2()
+            mat[i, i] = if (abs(dgrad.getGradientDerivative().getEntry(i)) > prec.eps2()
             ) 1.0 / dgrad.getGradientDerivative().getEntry(i) else 1.0
         }
         val err = MinimumError(mat, 1.0)
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/ScanBuilder.kt b/kmath-optimization/src/commonMain/tmp/minuit/ScanBuilder.kt
index 57f910a26..254281beb 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/ScanBuilder.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/ScanBuilder.kt
@@ -33,7 +33,7 @@ internal class ScanBuilder : MinimumBuilder {
         seed: MinimumSeed,
         stra: MnStrategy?,
         maxfcn: Int,
-        toler: Double
+        toler: Double,
     ): FunctionMinimum {
         val x: RealVector = seed.parameters().vec().copy()
         val upst = MnUserParameterState(seed.state(), mfcn.errorDef(), seed.trafo())
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/SimplexBuilder.kt b/kmath-optimization/src/commonMain/tmp/minuit/SimplexBuilder.kt
index 0b10155ff..08c4f40d0 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/SimplexBuilder.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/SimplexBuilder.kt
@@ -31,7 +31,7 @@ internal class SimplexBuilder : MinimumBuilder {
         seed: MinimumSeed,
         strategy: MnStrategy?,
         maxfcn: Int,
-        minedm: Double
+        minedm: Double,
     ): FunctionMinimum {
         val prec: MnMachinePrecision = seed.precision()
         val x: RealVector = seed.parameters().vec().copy()
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/SimplexSeedGenerator.kt b/kmath-optimization/src/commonMain/tmp/minuit/SimplexSeedGenerator.kt
index 577545fc3..21f1868eb 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/SimplexSeedGenerator.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/SimplexSeedGenerator.kt
@@ -41,8 +41,7 @@ internal class SimplexSeedGenerator : MinimumSeedGenerator {
         val mat = MnAlgebraicSymMatrix(n)
         val dcovar = 1.0
         for (i in 0 until n) {
-            mat[i, i] = if (abs(dgrad.getGradientDerivative()
-                    .getEntry(i)) > prec.eps2()
+            mat[i, i] = if (abs(dgrad.getGradientDerivative().getEntry(i)) > prec.eps2()
             ) 1.0 / dgrad.getGradientDerivative().getEntry(i) else 1.0
         }
         val err = MinimumError(mat, dcovar)
diff --git a/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricBuilder.kt b/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricBuilder.kt
index edc6783b6..a9e4faa36 100644
--- a/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricBuilder.kt
+++ b/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricBuilder.kt
@@ -41,7 +41,7 @@ internal class VariableMetricBuilder : MinimumBuilder {
         seed: MinimumSeed,
         strategy: MnStrategy,
         maxfcn: Int,
-        edmval: Double
+        edmval: Double,
     ): FunctionMinimum {
         val min: FunctionMinimum = minimum(fcn, gc, seed, maxfcn, edmval)
         if (strategy.strategy() === 2 || strategy.strategy() === 1 && min.error().dcovar() > 0.05) {
diff --git a/kmath-stat/README.md b/kmath-stat/README.md
index e7e0a4d92..63b8bc3b8 100644
--- a/kmath-stat/README.md
+++ b/kmath-stat/README.md
@@ -6,19 +6,8 @@
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-stat:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-stat:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-stat:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -27,6 +16,6 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-stat:0.4.0-dev-1")
+    implementation("space.kscience:kmath-stat:0.4.0")
 }
 ```
diff --git a/kmath-stat/build.gradle.kts b/kmath-stat/build.gradle.kts
index 000280def..8116a8925 100644
--- a/kmath-stat/build.gradle.kts
+++ b/kmath-stat/build.gradle.kts
@@ -2,10 +2,11 @@ plugins {
     id("space.kscience.gradle.mpp")
 }
 
-kscience{
+kscience {
     jvm()
     js()
     native()
+    wasm()
 }
 
 kotlin.sourceSets {
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt
index 806da5560..979c7a002 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt
index 999fbffbc..8f5a378bb 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt
index ae814254b..f425c6285 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt
@@ -1,12 +1,12 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.distributions
 
-import space.kscience.kmath.chains.Chain
-import space.kscience.kmath.operations.DoubleField.pow
+import space.kscience.kmath.chains.BlockingDoubleChain
+import space.kscience.kmath.operations.Float64Field.pow
 import space.kscience.kmath.random.RandomGenerator
 import space.kscience.kmath.samplers.GaussianSampler
 import space.kscience.kmath.samplers.InternalErf
@@ -24,7 +24,7 @@ public class NormalDistribution(public val sampler: GaussianSampler) : Distribut
         return exp(-0.5 * x1 * x1 - (ln(sampler.standardDeviation) + 0.5 * ln(2 * PI)))
     }
 
-    override fun sample(generator: RandomGenerator): Chain<Double> = sampler.sample(generator)
+    override fun sample(generator: RandomGenerator): BlockingDoubleChain = sampler.sample(generator)
 
     override fun cumulative(arg: Double): Double {
         val dev = arg - sampler.mean
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/UniformDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/UniformDistribution.kt
index 953be06fd..d0f13398c 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/UniformDistribution.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/UniformDistribution.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/MCScope.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/MCScope.kt
index 2049a84fc..149b5d85d 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/MCScope.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/MCScope.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/RandomChain.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/RandomChain.kt
index 7e0ee3cd4..34a92efe1 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/RandomChain.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/RandomChain.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,7 +7,7 @@ package space.kscience.kmath.random
 
 import space.kscience.kmath.chains.BlockingDoubleChain
 import space.kscience.kmath.chains.Chain
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 
 /**
  * A possibly stateful chain producing random values.
@@ -25,14 +25,15 @@ public class RandomChain<out R>(
 /**
  * Create a generic random chain with provided [generator]
  */
-public fun <R> RandomGenerator.chain(generator: suspend RandomGenerator.() -> R): RandomChain<R> = RandomChain(this, generator)
+public fun <R> RandomGenerator.chain(generator: suspend RandomGenerator.() -> R): RandomChain<R> =
+    RandomChain(this, generator)
 
 /**
  * A type-specific double chunk random chain
  */
 public class UniformDoubleChain(public val generator: RandomGenerator) : BlockingDoubleChain {
-    override fun nextBufferBlocking(size: Int): DoubleBuffer = generator.nextDoubleBuffer(size)
-    override suspend fun nextBuffer(size: Int): DoubleBuffer = nextBufferBlocking(size)
+    override fun nextBufferBlocking(size: Int): Float64Buffer = generator.nextDoubleBuffer(size)
+    override suspend fun nextBuffer(size: Int): Float64Buffer = nextBufferBlocking(size)
 
     override suspend fun fork(): UniformDoubleChain = UniformDoubleChain(generator.fork())
 }
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/RandomGenerator.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/RandomGenerator.kt
index f7388006e..8d8fd8612 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/RandomGenerator.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/random/RandomGenerator.kt
@@ -1,11 +1,11 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.random
 
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import kotlin.random.Random
 
 /**
@@ -25,7 +25,7 @@ public interface RandomGenerator {
     /**
      * A chunk of doubles of given [size].
      */
-    public fun nextDoubleBuffer(size: Int): DoubleBuffer = DoubleBuffer(size) { nextDouble() }
+    public fun nextDoubleBuffer(size: Int): Float64Buffer = Float64Buffer(size) { nextDouble() }
 
     /**
      * Gets the next random `Int` from the random number generator.
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt
index e5a48d4d8..0276cd654 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,7 +8,7 @@ package space.kscience.kmath.samplers
 import space.kscience.kmath.chains.BlockingDoubleChain
 import space.kscience.kmath.random.RandomGenerator
 import space.kscience.kmath.stat.Sampler
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import kotlin.math.ln
 import kotlin.math.pow
 
@@ -56,7 +56,7 @@ public class AhrensDieterExponentialSampler(public val mean: Double) : Sampler<D
             return mean * (a + umin * EXPONENTIAL_SA_QI[0])
         }
 
-        override fun nextBufferBlocking(size: Int): DoubleBuffer = DoubleBuffer(size) { nextBlocking() }
+        override fun nextBufferBlocking(size: Int): Float64Buffer = Float64Buffer(size) { nextBlocking() }
 
         override suspend fun fork(): BlockingDoubleChain = sample(generator.fork())
     }
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt
index d301ff637..05163387d 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt
index 2ec40c347..f65e8585b 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt
index 7795ff297..9f90d1626 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,7 +7,7 @@ package space.kscience.kmath.samplers
 
 import space.kscience.kmath.chains.BlockingDoubleChain
 import space.kscience.kmath.random.RandomGenerator
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import kotlin.math.*
 
 /**
@@ -22,11 +22,11 @@ public object BoxMullerSampler : NormalizedGaussianSampler {
     override fun sample(generator: RandomGenerator): BlockingDoubleChain = object : BlockingDoubleChain {
         var state = Double.NaN
 
-        override fun nextBufferBlocking(size: Int): DoubleBuffer {
+        override fun nextBufferBlocking(size: Int): Float64Buffer {
             val xs = generator.nextDoubleBuffer(size)
             val ys = generator.nextDoubleBuffer(size)
 
-            return DoubleBuffer(size) { index ->
+            return Float64Buffer(size) { index ->
                 if (state.isNaN()) {
                     // Generate a pair of Gaussian numbers.
                     val x = xs[index]
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt
index 28d588165..c86c6aa35 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalErf.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalErf.kt
index 0c1a5b36f..c28b4be50 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalErf.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalErf.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalGamma.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalGamma.kt
index 43c5a0d3c..08fefe322 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalGamma.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalGamma.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -123,7 +123,7 @@ internal object InternalGamma {
     private fun regularizedGammaP(
         a: Double,
         x: Double,
-        maxIterations: Int = Int.MAX_VALUE
+        maxIterations: Int = Int.MAX_VALUE,
     ): Double = when {
         a.isNaN() || x.isNaN() || a <= 0.0 || x < 0.0 -> Double.NaN
         x == 0.0 -> 0.0
@@ -155,7 +155,7 @@ internal object InternalGamma {
     fun regularizedGammaQ(
         a: Double,
         x: Double,
-        maxIterations: Int = Int.MAX_VALUE
+        maxIterations: Int = Int.MAX_VALUE,
     ): Double = when {
         a.isNaN() || x.isNaN() || a <= 0.0 || x < 0.0 -> Double.NaN
         x == 0.0 -> 1.0
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalUtils.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalUtils.kt
index 9f633e3db..cbc361b56 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalUtils.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/InternalUtils.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt
index 6d2899314..7a076d849 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,7 +8,7 @@ package space.kscience.kmath.samplers
 import space.kscience.kmath.chains.BlockingIntChain
 import space.kscience.kmath.random.RandomGenerator
 import space.kscience.kmath.stat.Sampler
-import space.kscience.kmath.structures.IntBuffer
+import space.kscience.kmath.structures.Int32Buffer
 import kotlin.math.exp
 
 /**
@@ -55,7 +55,7 @@ public class KempSmallMeanPoissonSampler internal constructor(
             return x
         }
 
-        override fun nextBufferBlocking(size: Int): IntBuffer = IntBuffer(size) { nextBlocking() }
+        override fun nextBufferBlocking(size: Int): Int32Buffer = Int32Buffer(size) { nextBlocking() }
 
         override suspend fun fork(): BlockingIntChain = sample(generator.fork())
     }
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt
index 3c3fe10fd..b1343a4ca 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,7 +7,7 @@ package space.kscience.kmath.samplers
 
 import space.kscience.kmath.chains.BlockingDoubleChain
 import space.kscience.kmath.random.RandomGenerator
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import kotlin.math.ln
 import kotlin.math.sqrt
 
@@ -59,7 +59,7 @@ public object MarsagliaNormalizedGaussianSampler : NormalizedGaussianSampler {
             }
         }
 
-        override fun nextBufferBlocking(size: Int): DoubleBuffer = DoubleBuffer(size) { nextBlocking() }
+        override fun nextBufferBlocking(size: Int): Float64Buffer = Float64Buffer(size) { nextBlocking() }
 
         override suspend fun fork(): BlockingDoubleChain = sample(generator.fork())
     }
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt
index 291d0bffe..81d1edb47 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt
index 454691e05..8faaf33dc 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -9,7 +9,7 @@ import space.kscience.kmath.chains.BlockingIntChain
 import space.kscience.kmath.misc.toIntExact
 import space.kscience.kmath.random.RandomGenerator
 import space.kscience.kmath.stat.Sampler
-import space.kscience.kmath.structures.IntBuffer
+import space.kscience.kmath.structures.Int32Buffer
 import kotlin.math.*
 
 
@@ -71,7 +71,7 @@ public class SmallMeanPoissonSampler(public val mean: Double) : Sampler<Int> {
             return n
         }
 
-        override fun nextBufferBlocking(size: Int): IntBuffer = IntBuffer(size) { nextBlocking() }
+        override fun nextBufferBlocking(size: Int): Int32Buffer = Int32Buffer(size) { nextBlocking() }
 
         override suspend fun fork(): BlockingIntChain = sample(generator.fork())
     }
@@ -191,7 +191,7 @@ public class LargeMeanPoissonSampler(public val mean: Double) : Sampler<Int> {
             return min(y2 + y.toLong(), Int.MAX_VALUE.toLong()).toIntExact()
         }
 
-        override fun nextBufferBlocking(size: Int): IntBuffer = IntBuffer(size) { nextBlocking() }
+        override fun nextBufferBlocking(size: Int): Int32Buffer = Int32Buffer(size) { nextBlocking() }
 
         override suspend fun fork(): BlockingIntChain = sample(generator.fork())
     }
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/Sampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/Sampler.kt
index b87a429df..44e099a52 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/Sampler.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/Sampler.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -12,8 +12,6 @@ import space.kscience.kmath.chains.combine
 import space.kscience.kmath.random.RandomGenerator
 import space.kscience.kmath.structures.Buffer
 import space.kscience.kmath.structures.BufferFactory
-import space.kscience.kmath.structures.DoubleBuffer
-import space.kscience.kmath.structures.IntBuffer
 import kotlin.jvm.JvmName
 
 /**
@@ -36,7 +34,7 @@ public fun interface Sampler<out T : Any> {
 public fun <T : Any> Sampler<T>.sampleBuffer(
     generator: RandomGenerator,
     size: Int,
-    bufferFactory: BufferFactory<T> = BufferFactory.boxing(),
+    bufferFactory: BufferFactory<T>,
 ): Chain<Buffer<T>> {
     require(size > 1)
     //creating temporary storage once
@@ -58,18 +56,11 @@ public fun <T : Any> Sampler<T>.sampleBuffer(
 public suspend fun <T : Any> Sampler<T>.next(generator: RandomGenerator): T = sample(generator).first()
 
 /**
- * Generates [size] real samples and chunks them into some buffers.
+ * Generates [size] samples and chunks them into some buffers.
  */
 @JvmName("sampleRealBuffer")
-public fun Sampler<Double>.sampleBuffer(generator: RandomGenerator, size: Int): Chain<Buffer<Double>> =
-    sampleBuffer(generator, size, ::DoubleBuffer)
-
-/**
- * Generates [size] integer samples and chunks them into some buffers.
- */
-@JvmName("sampleIntBuffer")
-public fun Sampler<Int>.sampleBuffer(generator: RandomGenerator, size: Int): Chain<Buffer<Int>> =
-    sampleBuffer(generator, size, ::IntBuffer)
+public inline fun <reified T : Any> Sampler<T>.sampleBuffer(generator: RandomGenerator, size: Int): Chain<Buffer<T>> =
+    sampleBuffer(generator, size, BufferFactory())
 
 
 /**
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/SamplerAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/SamplerAlgebra.kt
index 44b87a431..26d1b89a8 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/SamplerAlgebra.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/SamplerAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -14,6 +14,7 @@ import space.kscience.kmath.operations.ScaleOperations
 import space.kscience.kmath.operations.invoke
 import space.kscience.kmath.random.RandomGenerator
 import space.kscience.kmath.stat.Sampler
+import space.kscience.kmath.structures.MutableBufferFactory
 
 /**
  * Implements [Sampler] by sampling only certain [value].
@@ -41,6 +42,8 @@ public class BasicSampler<out T : Any>(public val chainBuilder: (RandomGenerator
 public class SamplerSpace<T : Any, out S>(public val algebra: S) : Group<Sampler<T>>,
     ScaleOperations<Sampler<T>> where S : Group<T>, S : ScaleOperations<T> {
 
+    override val bufferFactory: MutableBufferFactory<Sampler<T>> = MutableBufferFactory()
+
     override val zero: Sampler<T> = ConstantSampler(algebra.zero)
 
     override fun add(left: Sampler<T>, right: Sampler<T>): Sampler<T> = BasicSampler { generator ->
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt
index 40ce37d15..db04d94bd 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,7 +7,7 @@ package space.kscience.kmath.samplers
 
 import space.kscience.kmath.chains.BlockingDoubleChain
 import space.kscience.kmath.random.RandomGenerator
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import kotlin.math.*
 
 /**
@@ -63,7 +63,7 @@ public object ZigguratNormalizedGaussianSampler : NormalizedGaussianSampler {
     }
 
     override fun sample(generator: RandomGenerator): BlockingDoubleChain = object : BlockingDoubleChain {
-        override fun nextBufferBlocking(size: Int): DoubleBuffer = DoubleBuffer(size) { sampleOne(generator) }
+        override fun nextBufferBlocking(size: Int): Float64Buffer = Float64Buffer(size) { sampleOne(generator) }
 
         override suspend fun fork(): BlockingDoubleChain = sample(generator.fork())
     }
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/MonotonicSeriesAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/MonotonicSeriesAlgebra.kt
index ed6f4e07b..bd77974d1 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/MonotonicSeriesAlgebra.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/MonotonicSeriesAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2023 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/SeriesAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/SeriesAlgebra.kt
index cabff25e6..e47e4f69f 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/SeriesAlgebra.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/SeriesAlgebra.kt
@@ -1,3 +1,8 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
 package space.kscience.kmath.series
 
 import space.kscience.kmath.operations.BufferAlgebra
@@ -204,7 +209,7 @@ public open class SeriesAlgebra<T, out A : Ring<T>, out BA : BufferAlgebra<T, A>
      * */
     public inline fun Buffer<T>.zipWithShift(
         shift: Int = 1,
-        crossinline operation: A.(left: T, right: T) -> T
+        crossinline operation: A.(left: T, right: T) -> T,
     ): Buffer<T> {
         val shifted = this.moveBy(shift)
         return zip(shifted, operation)
@@ -216,7 +221,7 @@ public open class SeriesAlgebra<T, out A : Ring<T>, out BA : BufferAlgebra<T, A>
 
     override fun multiply(left: Buffer<T>, right: Buffer<T>): Buffer<T> = left.zip(right) { l, r -> l * r }
 
-    public fun Buffer<T>.difference(shift: Int=1): Buffer<T> = this.zipWithShift(shift) {l, r -> r - l}
+    public fun Buffer<T>.difference(shift: Int = 1): Buffer<T> = this.zipWithShift(shift) { l, r -> r - l }
 
     public companion object
 }
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/VarianceRatioTest.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/VarianceRatioTest.kt
index 4becb3413..337b13020 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/VarianceRatioTest.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/VarianceRatioTest.kt
@@ -1,12 +1,12 @@
 /*
- * Copyright 2018-2023 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.series
 
 import space.kscience.kmath.distributions.NormalDistribution
-import space.kscience.kmath.operations.DoubleField.pow
+import space.kscience.kmath.operations.Float64Field.pow
 import space.kscience.kmath.operations.fold
 import kotlin.math.absoluteValue
 
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/resampling.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/resampling.kt
index dc21fe6d9..9931429e7 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/resampling.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/resampling.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2023 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/seriesExtensions.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/seriesExtensions.kt
index fa5e0addd..92e3cf534 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/seriesExtensions.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/series/seriesExtensions.kt
@@ -1,3 +1,8 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
 package space.kscience.kmath.series
 
 import space.kscience.kmath.operations.BufferAlgebra
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt
index 3bf8b33e8..846e95b18 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -13,21 +13,20 @@ import space.kscience.kmath.structures.indices
  * Arithmetic mean
  */
 public class Mean<T>(
-    private val group: Ring<T>,
-    private val division: (sum: T, count: Int) -> T,
+    private val field: Field<T>,
 ) : ComposableStatistic<T, Pair<T, Int>, T>, BlockingStatistic<T, T> {
 
-    override fun evaluateBlocking(data: Buffer<T>): T = group {
+    override fun evaluateBlocking(data: Buffer<T>): T = with(field) {
         var res = zero
         for (i in data.indices) {
             res += data[i]
         }
-        division(res, data.size)
+        res / data.size
     }
 
     override suspend fun evaluate(data: Buffer<T>): T = super<ComposableStatistic>.evaluate(data)
 
-    override suspend fun computeIntermediate(data: Buffer<T>): Pair<T, Int> = group {
+    override suspend fun computeIntermediate(data: Buffer<T>): Pair<T, Int> = with(field) {
         var res = zero
         for (i in data.indices) {
             res += data[i]
@@ -36,32 +35,23 @@ public class Mean<T>(
     }
 
     override suspend fun composeIntermediate(first: Pair<T, Int>, second: Pair<T, Int>): Pair<T, Int> =
-        group { first.first + second.first } to (first.second + second.second)
+        with(field) { first.first + second.first } to (first.second + second.second)
 
-    override suspend fun toResult(intermediate: Pair<T, Int>): T = group {
-        division(intermediate.first, intermediate.second)
+    override suspend fun toResult(intermediate: Pair<T, Int>): T = with(field) {
+        intermediate.first / intermediate.second
     }
 
     public companion object {
-        @Deprecated("Use Double.mean instead")
-        public val double: Mean<Double> = Mean(DoubleField) { sum, count -> sum / count }
-
-        @Deprecated("Use Int.mean instead")
-        public val int: Mean<Int> = Mean(IntRing) { sum, count -> sum / count }
-
-        @Deprecated("Use Long.mean instead")
-        public val long: Mean<Long> = Mean(LongRing) { sum, count -> sum / count }
-
-        public fun evaluate(buffer: Buffer<Double>): Double = DoubleField.mean.evaluateBlocking(buffer)
-        public fun evaluate(buffer: Buffer<Int>): Int = IntRing.mean.evaluateBlocking(buffer)
-        public fun evaluate(buffer: Buffer<Long>): Long = LongRing.mean.evaluateBlocking(buffer)
+        public fun evaluate(buffer: Buffer<Double>): Double = Float64Field.mean.evaluateBlocking(buffer)
+        public fun evaluate(buffer: Buffer<Int>): Int = Int32Ring.mean.evaluateBlocking(buffer)
+        public fun evaluate(buffer: Buffer<Long>): Long = Int64Ring.mean.evaluateBlocking(buffer)
     }
 }
 
 
 //TODO replace with optimized version which respects overflow
-public val DoubleField.mean: Mean<Double> get() = Mean(DoubleField) { sum, count -> sum / count }
-public val IntRing.mean: Mean<Int> get() = Mean(IntRing) { sum, count -> sum / count }
-public val LongRing.mean: Mean<Long> get() = Mean(LongRing) { sum, count -> sum / count }
+public val Float64Field.mean: Mean<Double> get() = Mean(Float64Field)
+public val Int32Ring.mean: Mean<Int> get() = Mean(Int32Field)
+public val Int64Ring.mean: Mean<Long> get() = Mean(Int64Field)
 
 
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt
index 87046cd46..f0328839f 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt
@@ -1,21 +1,38 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.stat
 
-import space.kscience.kmath.operations.asSequence
+import space.kscience.kmath.misc.sortedWith
+import space.kscience.kmath.operations.*
 import space.kscience.kmath.structures.Buffer
 
 /**
  * Non-composable median
  */
-public class Median<T>(private val comparator: Comparator<T>) : BlockingStatistic<T, T> {
-    override fun evaluateBlocking(data: Buffer<T>): T =
-        data.asSequence().sortedWith(comparator).toList()[data.size / 2] //TODO check if this is correct
+public class Median<T>(private val field: Field<T>, private val comparator: Comparator<T>) : BlockingStatistic<T, T> {
+
+    override fun evaluateBlocking(data: Buffer<T>): T = when {
+        data.size == 0 -> error("Can't compute median of an empty buffer")
+        data.size == 1 -> data[0]
+        data.size % 2 == 0 -> with(field) {
+            val sorted = data.sortedWith(comparator)
+            (sorted[data.size / 2 - 1] + sorted[data.size / 2]) / 2
+        }
+
+        else -> data.sortedWith(comparator)[(data.size - 1) / 2]
+    }
 
     public companion object {
-        public val real: Median<Double> = Median { a: Double, b: Double -> a.compareTo(b) }
+
+        public fun evaluate(buffer: Buffer<Double>): Double = Float64Field.mean.evaluateBlocking(buffer)
+        public fun evaluate(buffer: Buffer<Int>): Int = Int32Ring.mean.evaluateBlocking(buffer)
+        public fun evaluate(buffer: Buffer<Long>): Long = Int64Ring.mean.evaluateBlocking(buffer)
     }
-}
\ No newline at end of file
+}
+
+public val Float64Field.median: Median<Double> get() = Median(Float64Field) { a, b -> a.compareTo(b) }
+public val Int32Ring.median: Median<Int> get() = Median(Int32Field) { a, b -> a.compareTo(b) }
+public val Int64Ring.median: Median<Long> get() = Median(Int64Field) { a, b -> a.compareTo(b) }
\ No newline at end of file
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Rank.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Rank.kt
index 5a873b466..cb309663e 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Rank.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Rank.kt
@@ -1,3 +1,8 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
 package space.kscience.kmath.stat
 
 import space.kscience.kmath.operations.asIterable
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt
index d7638ff81..81ed258f7 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -15,7 +15,7 @@ import space.kscience.kmath.coroutines.mapParallel
 import space.kscience.kmath.structures.Buffer
 
 /**
- * A function, that transforms a buffer of random quantities to some resulting value
+ * A function that transforms a buffer of random quantities to some resulting value
  */
 public fun interface Statistic<in T, out R> {
     public suspend fun evaluate(data: Buffer<T>): R
@@ -67,7 +67,7 @@ private fun <T, I, R> ComposableStatistic<T, I, R>.flowIntermediate(
 
 
 /**
- * Perform a streaming statistical analysis on a chunked data. The computation of inner representation is done in parallel
+ * Perform a streaming statistical analysis on chunked data. The computation of inner representation is done in parallel
  * if [dispatcher] allows it.
  *
  * The resulting flow contains values that include the whole previous statistics, not only the last chunk.
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/StatisticalAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/StatisticalAlgebra.kt
index cce61519b..9f0491b4b 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/StatisticalAlgebra.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/StatisticalAlgebra.kt
@@ -1,3 +1,8 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
 package space.kscience.kmath.stat
 
 import space.kscience.kmath.UnstableKMathAPI
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/ValueAndErrorField.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/ValueAndErrorField.kt
index 38cd5f900..dc9a10661 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/ValueAndErrorField.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/ValueAndErrorField.kt
@@ -1,14 +1,18 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.stat
 
+import space.kscience.attributes.SafeType
+import space.kscience.attributes.safeTypeOf
 import space.kscience.kmath.operations.Field
+import space.kscience.kmath.structures.*
 import kotlin.math.pow
 import kotlin.math.sqrt
 
+
 /**
  * A combination of a random [value] and its [dispersion].
  *
@@ -53,4 +57,46 @@ public object ValueAndErrorField : Field<ValueAndError> {
 
     override fun scale(a: ValueAndError, value: Double): ValueAndError =
         ValueAndError(a.value * value, a.dispersion * value.pow(2))
+
+
+    private class ValueAndErrorBuffer(val values: Float64Buffer, val ds: Float64Buffer) : MutableBuffer<ValueAndError> {
+        init {
+            require(values.size == ds.size)
+        }
+
+        override val size: Int
+            get() = values.size
+
+        override fun get(index: Int): ValueAndError = ValueAndError(values[index], ds[index])
+
+        override fun toString(): String = Buffer.toString(this)
+
+        override fun set(index: Int, value: ValueAndError) {
+            values[index] = value.value
+            values[index] = value.dispersion
+        }
+
+    }
+
+    override val bufferFactory: MutableBufferFactory<ValueAndError> = object : MutableBufferFactory<ValueAndError> {
+        override fun invoke(
+            size: Int,
+            builder: (Int) -> ValueAndError,
+        ): MutableBuffer<ValueAndError> {
+            val values: DoubleArray = DoubleArray(size)
+            val ds = DoubleArray(size)
+            repeat(size) {
+                val (v, d) = builder(it)
+                values[it] = v
+                ds[it] = d
+            }
+            return ValueAndErrorBuffer(
+                values.asBuffer(),
+                ds.asBuffer()
+            )
+        }
+
+        override val type: SafeType<ValueAndError> get() = safeTypeOf()
+
+    }
 }
\ No newline at end of file
diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/chiSquaredExpression.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/chiSquaredExpression.kt
index ca9755ad5..c42f149f2 100644
--- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/chiSquaredExpression.kt
+++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/chiSquaredExpression.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2023 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestSeries.kt b/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestSeries.kt
index d83abb3f4..461edcaf5 100644
--- a/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestSeries.kt
+++ b/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestSeries.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2023 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -16,13 +16,13 @@ import kotlin.test.assertEquals
 class TestSeries {
 
     @Test
-    fun zip() = with(Double.algebra.bufferAlgebra.seriesAlgebra()){
+    fun zip() = with(Double.algebra.bufferAlgebra.seriesAlgebra()) {
         val s1 = series(100) { sin(2 * PI * it / 100) + 1.0 }
 
         val s2 = s1.slice(20..50).moveTo(40)
 
         val s3: Buffer<Double> = s1.zip(s2) { l, r -> l + r } //s1 + s2
 
-        assertEquals(s3.getByOffset(40),s1.getByOffset(40) + s1.getByOffset(20))
+        assertEquals(s3.getByOffset(40), s1.getByOffset(40) + s1.getByOffset(20))
     }
 }
\ No newline at end of file
diff --git a/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestVarianceRatioTest.kt b/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestVarianceRatioTest.kt
index afc0d541d..1d34628c1 100644
--- a/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestVarianceRatioTest.kt
+++ b/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/series/TestVarianceRatioTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2023 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -32,7 +32,7 @@ class TestVarianceRatioTest {
     @Test
     fun volatileData() {
         with(Double.algebra.bufferAlgebra.seriesAlgebra()) {
-            val volatileData = series(10) { sin(PI * it + PI/2) + 1.0}
+            val volatileData = series(10) { sin(PI * it + PI / 2) + 1.0 }
             val resultHomo = varianceRatioTest(volatileData, 2)
             assertEquals(0.0, resultHomo.varianceRatio, 1e-6)
             // homoscedastic zScore
@@ -48,7 +48,7 @@ class TestVarianceRatioTest {
     @Test
     fun negativeData() {
         with(Double.algebra.bufferAlgebra.seriesAlgebra()) {
-            val negativeData = series(10) { sin(it * 1.2)}
+            val negativeData = series(10) { sin(it * 1.2) }
             val resultHomo = varianceRatioTest(negativeData, 3)
             assertEquals(1.240031, resultHomo.varianceRatio, 1e-6)
             // homoscedastic zScore
diff --git a/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/stat/TestBasicStatistics.kt b/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/stat/TestBasicStatistics.kt
new file mode 100644
index 000000000..0efc3c269
--- /dev/null
+++ b/kmath-stat/src/commonTest/kotlin/space/kscience/kmath/stat/TestBasicStatistics.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.stat
+
+import space.kscience.kmath.UnstableKMathAPI
+import space.kscience.kmath.operations.Float64Field
+import space.kscience.kmath.random.RandomGenerator
+import space.kscience.kmath.structures.slice
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+@OptIn(UnstableKMathAPI::class)
+class TestBasicStatistics {
+    companion object {
+        val float64Sample = RandomGenerator.default(123).nextDoubleBuffer(100)
+    }
+
+    @Test
+    fun medianFloat64() {
+        assertEquals(0.508, Float64Field.median(float64Sample), 0.0005)
+        assertEquals(0.5055, Float64Field.median(float64Sample.slice { 0..<last }), 0.0005)
+    }
+
+    @Test
+    fun meanFloat64() {
+        assertEquals(0.488, Float64Field.mean(float64Sample), 0.0002)
+    }
+}
\ No newline at end of file
diff --git a/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt b/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt
index 2c6391612..8badbce64 100644
--- a/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt
+++ b/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt
index b9b9dadba..227214d63 100644
--- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt
+++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt
index dbcf32e27..a58b84514 100644
--- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt
+++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -21,7 +21,7 @@ internal class MCScopeTest {
         mcScope(1111) {
             val res = Collections.synchronizedSet(HashSet<RandomResult>())
 
-            launch{
+            launch {
                 //println(random)
                 repeat(10) {
                     delay(10)
@@ -68,7 +68,7 @@ internal class MCScopeTest {
     }
 
 
-    @OptIn(DelicateCoroutinesApi::class)
+    @OptIn(DelicateCoroutinesApi::class, ExperimentalCoroutinesApi::class)
     fun compareResult(test: ATest) {
         val res1 = runBlocking(Dispatchers.Default) { test() }
         val res2 = runBlocking(newSingleThreadContext("test")) { test() }
diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt
index 0076006e6..fd2db98ae 100644
--- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt
+++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt
index 3be7fa314..fb9a4351a 100644
--- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt
+++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -9,7 +9,7 @@ import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.flow.last
 import kotlinx.coroutines.flow.take
 import kotlinx.coroutines.runBlocking
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.random.RandomGenerator
 import space.kscience.kmath.random.chain
 import space.kscience.kmath.streaming.chunked
@@ -29,20 +29,20 @@ internal class StatisticTest {
     @Test
     fun singleBlockingMean() {
         val first = runBlocking { chunked.first() }
-        val res = DoubleField.mean(first)
+        val res = Float64Field.mean(first)
         assertEquals(0.5, res, 1e-1)
     }
 
     @Test
     fun singleSuspendMean() = runBlocking {
         val first = runBlocking { chunked.first() }
-        val res = DoubleField.mean(first)
+        val res = Float64Field.mean(first)
         assertEquals(0.5, res, 1e-1)
     }
 
     @Test
     fun parallelMean() = runBlocking {
-        val average = DoubleField.mean
+        val average = Float64Field.mean
             .flow(chunked) //create a flow from evaluated results
             .take(100) // Take 100 data chunks from the source and accumulate them
             .last() //get 1e5 data samples average
diff --git a/kmath-symja/README.md b/kmath-symja/README.md
index 8672c6a71..a082d8b27 100644
--- a/kmath-symja/README.md
+++ b/kmath-symja/README.md
@@ -6,19 +6,8 @@ Symja integration module
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-symja:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-symja:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-symja:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -27,6 +16,6 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-symja:0.4.0-dev-1")
+    implementation("space.kscience:kmath-symja:0.4.0")
 }
 ```
diff --git a/kmath-symja/build.gradle.kts b/kmath-symja/build.gradle.kts
index 8741de2ae..a996f3bec 100644
--- a/kmath-symja/build.gradle.kts
+++ b/kmath-symja/build.gradle.kts
@@ -10,7 +10,7 @@ plugins {
 description = "Symja integration module"
 
 dependencies {
-    api("org.matheclipse:matheclipse-core:2.0.0-SNAPSHOT") {
+    api("org.matheclipse:matheclipse-core:2.0.0") {
         // Incorrect transitive dependencies
         exclude("org.apfloat", "apfloat")
         exclude("org.hipparchus", "hipparchus-clustering")
diff --git a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt
index 0f8014913..b23da37f5 100644
--- a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt
+++ b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,8 +7,9 @@ package space.kscience.kmath.symja
 
 import org.matheclipse.core.eval.ExprEvaluator
 import org.matheclipse.core.expression.F
-import space.kscience.kmath.expressions.SpecialDifferentiableExpression
+import space.kscience.attributes.SafeType
 import space.kscience.kmath.expressions.MST
+import space.kscience.kmath.expressions.SpecialDifferentiableExpression
 import space.kscience.kmath.expressions.Symbol
 import space.kscience.kmath.expressions.interpret
 import space.kscience.kmath.operations.NumericAlgebra
@@ -30,6 +31,8 @@ public class SymjaExpression<T : Number, A : NumericAlgebra<T>>(
     public val mst: MST,
     public val evaluator: ExprEvaluator = DEFAULT_EVALUATOR,
 ) : SpecialDifferentiableExpression<T, SymjaExpression<T, A>> {
+    override val type: SafeType<T> get() = algebra.type
+
     override fun invoke(arguments: Map<Symbol, T>): T = mst.interpret(algebra, arguments)
 
     override fun derivativeOrNull(symbols: List<Symbol>): SymjaExpression<T, A> = SymjaExpression(
diff --git a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt
index 92f2474b8..9590f2246 100644
--- a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt
+++ b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-tensorflow/README.md b/kmath-tensorflow/README.md
index a5b48de4d..6c289c808 100644
--- a/kmath-tensorflow/README.md
+++ b/kmath-tensorflow/README.md
@@ -6,19 +6,8 @@ Google tensorflow connector
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-tensorflow:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-tensorflow:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-tensorflow:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -27,6 +16,6 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-tensorflow:0.4.0-dev-1")
+    implementation("space.kscience:kmath-tensorflow:0.4.0")
 }
 ```
diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt
index 41c7c0b68..516a3a2ce 100644
--- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt
+++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -14,9 +14,11 @@ import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.expressions.Symbol
 import space.kscience.kmath.nd.ColumnStrides
+import space.kscience.kmath.nd.MutableStructureND
 import space.kscience.kmath.nd.ShapeND
 import space.kscience.kmath.nd.StructureND
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.FieldOps
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.PowerOperations
 
 public class DoubleTensorFlowOutput(
@@ -25,21 +27,21 @@ public class DoubleTensorFlowOutput(
 ) : TensorFlowOutput<Double, TFloat64>(graph, output) {
 
     override fun org.tensorflow.Tensor.actualizeTensor(): NdArray<Double> = this as TFloat64
-
 }
 
 internal fun ShapeND.toLongArray(): LongArray = LongArray(size) { get(it).toLong() }
 
 public class DoubleTensorFlowAlgebra internal constructor(
     graph: Graph,
-) : TensorFlowAlgebra<Double, TFloat64, DoubleField>(graph), PowerOperations<StructureND<Double>> {
+) : TensorFlowAlgebra<Double, TFloat64,
+        Float64Field>(graph), FieldOps<StructureND<Double>>, PowerOperations<StructureND<Double>> {
 
-    override val elementAlgebra: DoubleField get() = DoubleField
+    override val elementAlgebra: Float64Field get() = Float64Field
 
-    override fun structureND(
+    override fun mutableStructureND(
         shape: ShapeND,
-        initializer: DoubleField.(IntArray) -> Double,
-    ): StructureND<Double> {
+        initializer: Float64Field.(IntArray) -> Double,
+    ): MutableStructureND<Double> {
         val res = TFloat64.tensorOf(org.tensorflow.ndarray.Shape.of(*shape.toLongArray())) { array ->
             ColumnStrides(shape).forEach { index ->
                 array.setDouble(elementAlgebra.initializer(index), *index.toLongArray())
@@ -83,7 +85,7 @@ public class DoubleTensorFlowAlgebra internal constructor(
  * The resulting tensor is available outside of scope
  */
 @UnstableKMathAPI
-public fun DoubleField.produceWithTF(
+public fun Float64Field.produceWithTF(
     block: DoubleTensorFlowAlgebra.() -> StructureND<Double>,
 ): StructureND<Double> = Graph().use { graph ->
     val scope = DoubleTensorFlowAlgebra(graph)
@@ -96,7 +98,7 @@ public fun DoubleField.produceWithTF(
  * The resulting tensors are available outside of scope
  */
 @OptIn(UnstableKMathAPI::class)
-public fun DoubleField.produceMapWithTF(
+public fun Float64Field.produceMapWithTF(
     block: DoubleTensorFlowAlgebra.() -> Map<Symbol, StructureND<Double>>,
 ): Map<Symbol, StructureND<Double>> = Graph().use { graph ->
     val scope = DoubleTensorFlowAlgebra(graph)
diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt
index 01c8054b3..95ed52638 100644
--- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt
+++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -15,6 +15,7 @@ public class IntTensorFlowOutput(
     graph: Graph,
     output: Output<TInt32>,
 ) : TensorFlowOutput<Int, TInt32>(graph, output) {
+
     override fun org.tensorflow.Tensor.actualizeTensor(): NdArray<Int> = this as TInt32
 }
 
@@ -22,5 +23,6 @@ public class LongTensorFlowOutput(
     graph: Graph,
     output: Output<TInt64>,
 ) : TensorFlowOutput<Long, TInt64>(graph, output) {
+
     override fun org.tensorflow.Tensor.actualizeTensor(): NdArray<Long> = this as TInt64
 }
\ No newline at end of file
diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt
index 73b36cd67..2a8720275 100644
--- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt
+++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -41,6 +41,7 @@ public sealed interface TensorFlowTensor<T> : Tensor<T>
  */
 @JvmInline
 public value class TensorFlowArray<T>(public val tensor: NdArray<T>) : Tensor<T> {
+
     override val shape: ShapeND get() = ShapeND(tensor.shape().asArray().toIntArray())
 
     @PerformancePitfall
diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt
index a0a2ddc80..885b9fca6 100644
--- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt
+++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt b/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt
index 730feede6..eefc39a11 100644
--- a/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt
+++ b/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -10,7 +10,7 @@ import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.nd.ShapeND
 import space.kscience.kmath.nd.get
 import space.kscience.kmath.nd.structureND
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
 import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.sum
 import space.kscience.kmath.tensors.core.randomNormal
@@ -20,7 +20,7 @@ import kotlin.test.assertEquals
 class DoubleTensorFlowOps {
     @Test
     fun basicOps() {
-        val res = DoubleField.produceWithTF {
+        val res = Float64Field.produceWithTF {
             val initial = structureND(2, 2) { 1.0 }
 
             initial + (initial * 2.0)
@@ -30,26 +30,26 @@ class DoubleTensorFlowOps {
     }
 
     @Test
-    fun dot(){
+    fun dot() {
         val dim = 1000
 
         val tensor1 = DoubleTensorAlgebra.randomNormal(shape = ShapeND(dim, dim), 12224)
         val tensor2 = DoubleTensorAlgebra.randomNormal(shape = ShapeND(dim, dim), 12225)
 
-        DoubleField.produceWithTF {
+        Float64Field.produceWithTF {
             tensor1 dot tensor2
         }.sum()
     }
 
     @Test
-    fun extensionOps(){
-        val res = DoubleField.produceWithTF {
+    fun extensionOps() {
+        val res = Float64Field.produceWithTF {
             val i = structureND(2, 2) { 0.5 }
 
             sin(i).pow(2) + cos(i).pow(2)
         }
 
-        assertEquals(1.0, res[0,0],0.01)
+        assertEquals(1.0, res[0, 0], 0.01)
     }
 
 
diff --git a/kmath-tensors/README.md b/kmath-tensors/README.md
index 80f751ffe..92f99028b 100644
--- a/kmath-tensors/README.md
+++ b/kmath-tensors/README.md
@@ -9,19 +9,8 @@ Common linear algebra operations on tensors.
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-tensors:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-tensors:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-tensors:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -30,6 +19,6 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-tensors:0.4.0-dev-1")
+    implementation("space.kscience:kmath-tensors:0.4.0")
 }
 ```
diff --git a/kmath-tensors/build.gradle.kts b/kmath-tensors/build.gradle.kts
index 79c39bae7..64b253044 100644
--- a/kmath-tensors/build.gradle.kts
+++ b/kmath-tensors/build.gradle.kts
@@ -2,10 +2,17 @@ plugins {
     id("space.kscience.gradle.mpp")
 }
 
-kscience{
+kscience {
     jvm()
-    js()
+    js {
+        browser {
+            testTask {
+                useMocha().timeout = "0"
+            }
+        }
+    }
     native()
+    wasm()
 
     dependencies {
         api(projects.kmathCore)
@@ -22,8 +29,8 @@ kotlin.sourceSets {
         }
     }
 
-    commonTest{
-        dependencies{
+    commonTest {
+        dependencies {
             implementation(projects.testUtils)
         }
     }
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt
index 1a324b200..c8546094e 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -90,15 +90,15 @@ public interface AnalyticTensorAlgebra<T, A : Field<T>> :
     //For information: https://pytorch.org/docs/stable/generated/torch.floor.html#torch.floor
     public fun floor(structureND: StructureND<T>): Tensor<T>
 
-    override fun sin(arg: StructureND<T>): StructureND<T> 
+    override fun sin(arg: StructureND<T>): StructureND<T>
 
-    override fun cos(arg: StructureND<T>): StructureND<T> 
+    override fun cos(arg: StructureND<T>): StructureND<T>
 
     override fun asin(arg: StructureND<T>): StructureND<T>
 
     override fun acos(arg: StructureND<T>): StructureND<T>
 
-    override fun exp(arg: StructureND<T>): StructureND<T> 
+    override fun exp(arg: StructureND<T>): StructureND<T>
 
     override fun ln(arg: StructureND<T>): StructureND<T>
 
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt
index faff2eb80..f9f0ed832 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt
@@ -1,10 +1,11 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.tensors.api
 
+import space.kscience.kmath.nd.MutableStructure2D
 import space.kscience.kmath.nd.StructureND
 import space.kscience.kmath.operations.Field
 
@@ -103,4 +104,11 @@ public interface LinearOpsTensorAlgebra<T, A : Field<T>> : TensorPartialDivision
      */
     public fun symEig(structureND: StructureND<T>): Pair<StructureND<T>, StructureND<T>>
 
+    /** Returns the solution to the equation Ax = B for the square matrix A as `input1` and
+     * for the square matrix B as `input2`.
+     *
+     * @receiver the `input1` and the `input2`.
+     * @return the square matrix x which is the solution of the equation.
+     */
+    public fun solve(a: MutableStructure2D<Double>, b: MutableStructure2D<Double>): MutableStructure2D<Double>
 }
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt
deleted file mode 100644
index b328fbeec..000000000
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Copyright 2018-2022 KMath contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package space.kscience.kmath.tensors.api
-
-import space.kscience.kmath.nd.MutableStructureND
-
-public typealias Tensor<T> = MutableStructureND<T>
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt
index f923400c5..c960090d2 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt
@@ -1,15 +1,18 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.tensors.api
 
+import space.kscience.kmath.nd.MutableStructureND
 import space.kscience.kmath.nd.RingOpsND
 import space.kscience.kmath.nd.ShapeND
 import space.kscience.kmath.nd.StructureND
 import space.kscience.kmath.operations.Ring
 
+public typealias Tensor<T> = MutableStructureND<T>
+
 /**
  * Algebra over a ring on [Tensor].
  * For more information: https://proofwiki.org/wiki/Definition:Algebra_over_Ring
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt
index 33effb2d2..df8c32007 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt
index 7db91722f..d02a9f99e 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,7 +7,7 @@ package space.kscience.kmath.tensors.core
 
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.nd.StructureND
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import space.kscience.kmath.tensors.api.Tensor
 import space.kscience.kmath.tensors.core.internal.broadcastTensors
 import space.kscience.kmath.tensors.core.internal.broadcastTo
@@ -22,7 +22,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() {
         val broadcast = broadcastTensors(asDoubleTensor(), arg.asDoubleTensor())
         val newThis = broadcast[0]
         val newOther = broadcast[1]
-        val resBuffer = DoubleBuffer(newThis.indices.linearSize) { i ->
+        val resBuffer = Float64Buffer(newThis.indices.linearSize) { i ->
             newThis.source[i] + newOther.source[i]
         }
         return DoubleTensor(newThis.shape, resBuffer)
@@ -39,7 +39,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() {
         val broadcast = broadcastTensors(asDoubleTensor(), arg.asDoubleTensor())
         val newThis = broadcast[0]
         val newOther = broadcast[1]
-        val resBuffer = DoubleBuffer(newThis.indices.linearSize) { i ->
+        val resBuffer = Float64Buffer(newThis.indices.linearSize) { i ->
             newThis.source[i] - newOther.source[i]
         }
         return DoubleTensor(newThis.shape, resBuffer)
@@ -56,7 +56,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() {
         val broadcast = broadcastTensors(asDoubleTensor(), arg.asDoubleTensor())
         val newThis = broadcast[0]
         val newOther = broadcast[1]
-        val resBuffer = DoubleBuffer(newThis.indices.linearSize) { i ->
+        val resBuffer = Float64Buffer(newThis.indices.linearSize) { i ->
             newThis.source[i] * newOther.source[i]
         }
         return DoubleTensor(newThis.shape, resBuffer)
@@ -73,7 +73,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() {
         val broadcast = broadcastTensors(asDoubleTensor(), arg.asDoubleTensor())
         val newThis = broadcast[0]
         val newOther = broadcast[1]
-        val resBuffer = DoubleBuffer(newThis.indices.linearSize) { i ->
+        val resBuffer = Float64Buffer(newThis.indices.linearSize) { i ->
             newThis.source[i] / newOther.source[i]
         }
         return DoubleTensor(newThis.shape, resBuffer)
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt
index eaec43e2c..a595c94f5 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt
index d2c2e9d5d..b3c2eb1b4 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -13,7 +13,7 @@ import space.kscience.kmath.structures.*
 import space.kscience.kmath.tensors.core.internal.toPrettyString
 
 public class OffsetDoubleBuffer(
-    override val origin: DoubleBuffer,
+    override val origin: Float64Buffer,
     private val offset: Int,
     override val size: Int,
 ) : MutableBuffer<Double>, BufferView<Double> {
@@ -34,7 +34,7 @@ public class OffsetDoubleBuffer(
     /**
      * Copy only a part of buffer that belongs to this [OffsetDoubleBuffer]
      */
-    override fun copy(): DoubleBuffer = origin.array.copyOfRange(offset, offset + size).asBuffer()
+    public fun copy(): Float64Buffer = origin.array.copyOfRange(offset, offset + size).asBuffer()
 
     override fun iterator(): Iterator<Double> = iterator {
         for (i in indices) {
@@ -60,15 +60,15 @@ public fun OffsetDoubleBuffer.slice(range: IntRange): OffsetDoubleBuffer = view(
 /**
  * Map only operable content of the offset buffer
  */
-public inline fun OffsetDoubleBuffer.map(operation: (Double) -> Double): DoubleBuffer =
-    DoubleBuffer(size) { operation(get(it)) }
+public inline fun OffsetDoubleBuffer.map(operation: (Double) -> Double): Float64Buffer =
+    Float64Buffer(size) { operation(get(it)) }
 
 public inline fun OffsetDoubleBuffer.zip(
     other: OffsetDoubleBuffer,
     operation: (l: Double, r: Double) -> Double,
-): DoubleBuffer {
+): Float64Buffer {
     require(size == other.size) { "The sizes of zipped buffers must be the same" }
-    return DoubleBuffer(size) { operation(get(it), other[it]) }
+    return Float64Buffer(size) { operation(get(it), other[it]) }
 }
 
 /**
@@ -92,7 +92,7 @@ public open class DoubleTensor(
         require(linearSize == source.size) { "Source buffer size must be equal tensor size" }
     }
 
-    public constructor(shape: ShapeND, buffer: DoubleBuffer) : this(shape, OffsetDoubleBuffer(buffer, 0, buffer.size))
+    public constructor(shape: ShapeND, buffer: Float64Buffer) : this(shape, OffsetDoubleBuffer(buffer, 0, buffer.size))
 
 
     @OptIn(PerformancePitfall::class)
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor1D.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor1D.kt
index d2066e404..05f1b2f20 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor1D.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor1D.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,7 +8,6 @@ package space.kscience.kmath.tensors.core
 import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.nd.MutableStructure1D
 import space.kscience.kmath.nd.ShapeND
-import space.kscience.kmath.structures.MutableBuffer
 
 public class DoubleTensor1D(
     source: OffsetDoubleBuffer,
@@ -30,8 +29,6 @@ public class DoubleTensor1D(
         source[index] = value
     }
 
-    override fun copy(): MutableBuffer<Double> = source.copy()
-
     @PerformancePitfall
     override fun elements(): Sequence<Pair<IntArray, Double>> = super<MutableStructure1D>.elements()
 }
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor2D.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor2D.kt
index fa142afa0..013dfe791 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor2D.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor2D.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt
index 70a3ef7e2..0024f41ad 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -10,8 +10,8 @@ package space.kscience.kmath.tensors.core
 
 import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.nd.*
-import space.kscience.kmath.operations.DoubleBufferOps
-import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.operations.Float64BufferOps
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.structures.*
 import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra
 import space.kscience.kmath.tensors.api.LinearOpsTensorAlgebra
@@ -27,14 +27,14 @@ import kotlin.math.sqrt
  */
 @OptIn(PerformancePitfall::class)
 public open class DoubleTensorAlgebra :
-    AnalyticTensorAlgebra<Double, DoubleField>,
-    LinearOpsTensorAlgebra<Double, DoubleField> {
+    AnalyticTensorAlgebra<Double, Float64Field>,
+    LinearOpsTensorAlgebra<Double, Float64Field> {
 
     public companion object : DoubleTensorAlgebra()
 
-    override val elementAlgebra: DoubleField get() = DoubleField
+    override val elementAlgebra: Float64Field get() = Float64Field
 
-    public val bufferAlgebra: DoubleBufferOps get() = DoubleBufferOps
+    public val bufferAlgebra: Float64BufferOps get() = Float64BufferOps
 
 
     /**
@@ -44,10 +44,10 @@ public open class DoubleTensorAlgebra :
      * @return the resulting tensor after applying the function.
      */
     @Suppress("OVERRIDE_BY_INLINE")
-    final override inline fun StructureND<Double>.map(transform: DoubleField.(Double) -> Double): DoubleTensor {
+    final override inline fun StructureND<Double>.map(transform: Float64Field.(Double) -> Double): DoubleTensor {
         val tensor = asDoubleTensor()
         //TODO remove additional copy
-        val array = DoubleBuffer(tensor.source.size) { DoubleField.transform(tensor.source[it]) }
+        val array = Float64Buffer(tensor.source.size) { Float64Field.transform(tensor.source[it]) }
         return DoubleTensor(
             tensor.shape,
             array,
@@ -62,12 +62,12 @@ public open class DoubleTensorAlgebra :
         }
     }
 
-    public inline fun Tensor<Double>.mapIndexedInPlace(operation: DoubleField.(IntArray, Double) -> Double) {
-        indices.forEach { set(it, DoubleField.operation(it, get(it))) }
+    public inline fun Tensor<Double>.mapIndexedInPlace(operation: Float64Field.(IntArray, Double) -> Double) {
+        indices.forEach { set(it, Float64Field.operation(it, get(it))) }
     }
 
     @Suppress("OVERRIDE_BY_INLINE")
-    final override inline fun StructureND<Double>.mapIndexed(transform: DoubleField.(index: IntArray, Double) -> Double): DoubleTensor {
+    final override inline fun StructureND<Double>.mapIndexed(transform: Float64Field.(index: IntArray, Double) -> Double): DoubleTensor {
         return copyToTensor().apply { mapIndexedInPlace(transform) }
     }
 
@@ -76,20 +76,20 @@ public open class DoubleTensorAlgebra :
     final override inline fun zip(
         left: StructureND<Double>,
         right: StructureND<Double>,
-        transform: DoubleField.(Double, Double) -> Double,
+        transform: Float64Field.(Double, Double) -> Double,
     ): DoubleTensor {
         checkShapesCompatible(left, right)
 
         val leftTensor = left.asDoubleTensor()
         val rightTensor = right.asDoubleTensor()
-        val buffer = DoubleBuffer(leftTensor.source.size) {
-            DoubleField.transform(leftTensor.source[it], rightTensor.source[it])
+        val buffer = Float64Buffer(leftTensor.source.size) {
+            Float64Field.transform(leftTensor.source[it], rightTensor.source[it])
         }
         return DoubleTensor(leftTensor.shape, buffer)
     }
 
 
-    public inline fun StructureND<Double>.reduceElements(transform: (DoubleBuffer) -> Double): Double =
+    public inline fun StructureND<Double>.reduceElements(transform: (Float64Buffer) -> Double): Double =
         transform(asDoubleTensor().source.copy())
     //TODO Add read-only DoubleBuffer wrapper. To avoid protective copy
 
@@ -107,7 +107,7 @@ public open class DoubleTensorAlgebra :
         check(buffer.size == shape.linearSize) {
             "Inconsistent shape $shape for buffer of size ${buffer.size} provided"
         }
-        return DoubleTensor(shape, buffer.toDoubleBuffer())
+        return DoubleTensor(shape, buffer.toFloat64Buffer())
     }
 
 
@@ -127,10 +127,11 @@ public open class DoubleTensorAlgebra :
      * @param initializer mapping tensor indices to values.
      * @return tensor with the [shape] shape and data generated by the [initializer].
      */
-    override fun structureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): DoubleTensor = fromArray(
-        shape,
-        RowStrides(shape).asSequence().map { DoubleField.initializer(it) }.toMutableList().toDoubleArray()
-    )
+    override fun mutableStructureND(shape: ShapeND, initializer: Float64Field.(IntArray) -> Double): DoubleTensor =
+        fromArray(
+            shape,
+            RowStrides(shape).asSequence().map { Float64Field.initializer(it) }.toMutableList().toDoubleArray()
+        )
 
     override fun Tensor<Double>.getTensor(i: Int): DoubleTensor {
         val dt = asDoubleTensor()
@@ -151,7 +152,7 @@ public open class DoubleTensorAlgebra :
      */
     public fun full(value: Double, shape: ShapeND): DoubleTensor {
         checkNotEmptyShape(shape)
-        val buffer = DoubleBuffer(shape.linearSize) { value }
+        val buffer = Float64Buffer(shape.linearSize) { value }
         return DoubleTensor(shape, buffer)
     }
 
@@ -163,7 +164,7 @@ public open class DoubleTensorAlgebra :
      */
     public fun fullLike(structureND: StructureND<*>, value: Double): DoubleTensor {
         val shape = structureND.shape
-        val buffer = DoubleBuffer(structureND.indices.linearSize) { value }
+        val buffer = Float64Buffer(structureND.indices.linearSize) { value }
         return DoubleTensor(shape, buffer)
     }
 
@@ -205,7 +206,7 @@ public open class DoubleTensorAlgebra :
      */
     public fun eye(n: Int): DoubleTensor {
         val shape = ShapeND(n, n)
-        val buffer = DoubleBuffer(n * n) { 0.0 }
+        val buffer = Float64Buffer(n * n) { 0.0 }
         val res = DoubleTensor(shape, buffer)
         for (i in 0 until n) {
             res[intArrayOf(i, i)] = 1.0
@@ -353,7 +354,7 @@ public open class DoubleTensorAlgebra :
      */
     public infix fun StructureND<Double>.matmul(other: StructureND<Double>): DoubleTensor {
         if (shape.size == 1 && other.shape.size == 1) {
-            return DoubleTensor(ShapeND(1), DoubleBuffer(times(other).sum()))
+            return DoubleTensor(ShapeND(1), Float64Buffer(times(other).sum()))
         }
 
         var penultimateDim = false
@@ -529,7 +530,7 @@ public open class DoubleTensorAlgebra :
         val init = foldFunction(DoubleArray(1) { 0.0 })
         val resTensor = DoubleTensor(
             resShape,
-            DoubleBuffer(resNumElements) { init }
+            Float64Buffer(resNumElements) { init }
         )
         val dt = asDoubleTensor()
         for (index in resTensor.indices) {
@@ -557,7 +558,7 @@ public open class DoubleTensorAlgebra :
         val init = foldFunction(DoubleArray(1) { 0.0 })
         val resTensor = IntTensor(
             resShape,
-            IntBuffer(resNumElements) { init }
+            Int32Buffer(resNumElements) { init }
         )
         for (index in resTensor.indices) {
             val prefix = index.take(dim).toIntArray()
@@ -706,14 +707,18 @@ public open class DoubleTensorAlgebra :
     override fun svd(
         structureND: StructureND<Double>,
     ): Triple<StructureND<Double>, StructureND<Double>, StructureND<Double>> =
-        svd(structureND = structureND, epsilon = 1e-10)
+        svdGolubKahan(structureND = structureND, epsilon = 1e-10)
 
     override fun symEig(structureND: StructureND<Double>): Pair<DoubleTensor, DoubleTensor> =
         symEigJacobi(structureND = structureND, maxIteration = 50, epsilon = 1e-15)
 
+    override fun solve(a: MutableStructure2D<Double>, b: MutableStructure2D<Double>): MutableStructure2D<Double> {
+        val aSvd = DoubleTensorAlgebra.svd(a)
+        val s = BroadcastDoubleTensorAlgebra.diagonalEmbedding(aSvd.second.map { 1.0 / it })
+        val aInverse = aSvd.third.dot(s).dot(aSvd.first.transposed())
+        return aInverse.dot(b).as2D()
+    }
 }
 
 public val Double.Companion.tensorAlgebra: DoubleTensorAlgebra get() = DoubleTensorAlgebra
-public val DoubleField.tensorAlgebra: DoubleTensorAlgebra get() = DoubleTensorAlgebra
-
-
+public val Float64Field.tensorAlgebra: DoubleTensorAlgebra get() = DoubleTensorAlgebra
\ No newline at end of file
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt
index f028e2cbb..eb95d5e70 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -13,7 +13,7 @@ import space.kscience.kmath.structures.*
  * Default [BufferedTensor] implementation for [Int] values
  */
 public class OffsetIntBuffer(
-    private val source: IntBuffer,
+    private val source: Int32Buffer,
     private val offset: Int,
     override val size: Int,
 ) : MutableBuffer<Int> {
@@ -34,7 +34,7 @@ public class OffsetIntBuffer(
     /**
      * Copy only a part of buffer that belongs to this tensor
      */
-    override fun copy(): IntBuffer = source.array.copyOfRange(offset, offset + size).asBuffer()
+    public fun copy(): Int32Buffer = source.array.copyOfRange(offset, offset + size).asBuffer()
 
     override fun iterator(): Iterator<Int> = iterator {
         for (i in indices) {
@@ -53,15 +53,15 @@ public fun OffsetIntBuffer.slice(range: IntRange): OffsetIntBuffer = view(range.
 /**
  * Map only operable content of the offset buffer
  */
-public inline fun OffsetIntBuffer.map(operation: (Int) -> Int): IntBuffer =
-    IntBuffer(size) { operation(get(it)) }
+public inline fun OffsetIntBuffer.map(operation: (Int) -> Int): Int32Buffer =
+    Int32Buffer(size) { operation(get(it)) }
 
 public inline fun OffsetIntBuffer.zip(
     other: OffsetIntBuffer,
     operation: (l: Int, r: Int) -> Int,
-): IntBuffer {
+): Int32Buffer {
     require(size == other.size) { "The sizes of zipped buffers must be the same" }
-    return IntBuffer(size) { operation(get(it), other[it]) }
+    return Int32Buffer(size) { operation(get(it), other[it]) }
 }
 
 /**
@@ -83,7 +83,8 @@ public class IntTensor(
         require(linearSize == source.size) { "Source buffer size must be equal tensor size" }
     }
 
-    public constructor(shape: ShapeND, buffer: IntBuffer) : this(shape, OffsetIntBuffer(buffer, 0, buffer.size))
+
+    public constructor(shape: ShapeND, buffer: Int32Buffer) : this(shape, OffsetIntBuffer(buffer, 0, buffer.size))
 
     @OptIn(PerformancePitfall::class)
     override fun get(index: IntArray): Int = this.source[indices.offset(index)]
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt
index d1cdc68d4..e75564ef5 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -10,7 +10,7 @@ package space.kscience.kmath.tensors.core
 
 import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.nd.*
-import space.kscience.kmath.operations.IntRing
+import space.kscience.kmath.operations.Int32Ring
 import space.kscience.kmath.structures.*
 import space.kscience.kmath.tensors.api.*
 import space.kscience.kmath.tensors.core.internal.*
@@ -19,12 +19,12 @@ import kotlin.math.*
 /**
  * Implementation of basic operations over double tensors and basic algebra operations on them.
  */
-public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
+public open class IntTensorAlgebra : TensorAlgebra<Int, Int32Ring> {
 
     public companion object : IntTensorAlgebra()
 
 
-    override val elementAlgebra: IntRing get() = IntRing
+    override val elementAlgebra: Int32Ring get() = Int32Ring
 
 
     /**
@@ -34,10 +34,10 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
      * @return the resulting tensor after applying the function.
      */
     @Suppress("OVERRIDE_BY_INLINE")
-    final override inline fun StructureND<Int>.map(transform: IntRing.(Int) -> Int): IntTensor {
+    final override inline fun StructureND<Int>.map(transform: Int32Ring.(Int) -> Int): IntTensor {
         val tensor = this.asIntTensor()
         //TODO remove additional copy
-        val array = IntBuffer(tensor.source.size) { IntRing.transform(tensor.source[it]) }
+        val array = Int32Buffer(tensor.source.size) { Int32Ring.transform(tensor.source[it]) }
         return IntTensor(
             tensor.shape,
             array,
@@ -57,11 +57,11 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
     }
 
     @Suppress("OVERRIDE_BY_INLINE")
-    final override inline fun StructureND<Int>.mapIndexed(transform: IntRing.(index: IntArray, Int) -> Int): IntTensor {
+    final override inline fun StructureND<Int>.mapIndexed(transform: Int32Ring.(index: IntArray, Int) -> Int): IntTensor {
         val tensor = this.asIntTensor()
         //TODO remove additional copy
-        val buffer = IntBuffer(tensor.source.size) {
-            IntRing.transform(tensor.indices.index(it), tensor.source[it])
+        val buffer = Int32Buffer(tensor.source.size) {
+            Int32Ring.transform(tensor.indices.index(it), tensor.source[it])
         }
         return IntTensor(tensor.shape, buffer)
     }
@@ -70,20 +70,20 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
     final override inline fun zip(
         left: StructureND<Int>,
         right: StructureND<Int>,
-        transform: IntRing.(Int, Int) -> Int,
+        transform: Int32Ring.(Int, Int) -> Int,
     ): IntTensor {
         checkShapesCompatible(left, right)
 
         val leftTensor = left.asIntTensor()
         val rightTensor = right.asIntTensor()
-        val buffer = IntBuffer(leftTensor.source.size) {
-            IntRing.transform(leftTensor.source[it], rightTensor.source[it])
+        val buffer = Int32Buffer(leftTensor.source.size) {
+            Int32Ring.transform(leftTensor.source[it], rightTensor.source[it])
         }
         return IntTensor(leftTensor.shape, buffer)
     }
 
 
-    public inline fun StructureND<Int>.reduceElements(transform: (IntBuffer) -> Int): Int =
+    public inline fun StructureND<Int>.reduceElements(transform: (Int32Buffer) -> Int): Int =
         transform(asIntTensor().source.copy())
     //TODO do we need protective copy?
 
@@ -118,9 +118,9 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
      * @param initializer mapping tensor indices to values.
      * @return tensor with the [shape] shape and data generated by the [initializer].
      */
-    override fun structureND(shape: ShapeND, initializer: IntRing.(IntArray) -> Int): IntTensor = fromArray(
+    override fun mutableStructureND(shape: ShapeND, initializer: Int32Ring.(IntArray) -> Int): IntTensor = fromArray(
         shape,
-        RowStrides(shape).asSequence().map { IntRing.initializer(it) }.toMutableList().toIntArray()
+        RowStrides(shape).asSequence().map { Int32Ring.initializer(it) }.toMutableList().toIntArray()
     )
 
     override fun Tensor<Int>.getTensor(i: Int): IntTensor {
@@ -139,7 +139,7 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
      */
     public fun full(value: Int, shape: ShapeND): IntTensor {
         checkNotEmptyShape(shape)
-        val buffer = IntBuffer(shape.linearSize) { value }
+        val buffer = Int32Buffer(shape.linearSize) { value }
         return IntTensor(shape, buffer)
     }
 
@@ -151,7 +151,7 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
      */
     public fun fullLike(structureND: StructureND<*>, value: Int): IntTensor {
         val shape = structureND.shape
-        val buffer = IntBuffer(structureND.indices.linearSize) { value }
+        val buffer = Int32Buffer(structureND.indices.linearSize) { value }
         return IntTensor(shape, buffer)
     }
 
@@ -193,7 +193,7 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
      */
     public fun eye(n: Int): IntTensor {
         val shape = ShapeND(n, n)
-        val buffer = IntBuffer(n * n) { 0 }
+        val buffer = Int32Buffer(n * n) { 0 }
         val res = IntTensor(shape, buffer)
         for (i in 0 until n) {
             res[intArrayOf(i, i)] = 1
@@ -252,7 +252,7 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
 
     override fun StructureND<Int>.transposed(i: Int, j: Int): Tensor<Int> {
         val actualI = if (i >= 0) i else shape.size + i
-        val actualJ = if(j>=0) j else shape.size + j
+        val actualJ = if (j >= 0) j else shape.size + j
         return asIntTensor().permute(
             shape.transposed(actualI, actualJ)
         ) { originIndex ->
@@ -420,7 +420,7 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
         val init = foldFunction(IntArray(1) { 0 })
         val resTensor = IntTensor(
             resShape,
-            IntBuffer(resNumElements) { init }
+            Int32Buffer(resNumElements) { init }
         )
         for (index in resTensor.indices) {
             val prefix = index.take(dim).toIntArray()
@@ -462,6 +462,6 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
 }
 
 public val Int.Companion.tensorAlgebra: IntTensorAlgebra get() = IntTensorAlgebra
-public val IntRing.tensorAlgebra: IntTensorAlgebra get() = IntTensorAlgebra
+public val Int32Ring.tensorAlgebra: IntTensorAlgebra get() = IntTensorAlgebra
 
 
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/LevenbergMarquardtAlgorithm.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/LevenbergMarquardtAlgorithm.kt
new file mode 100644
index 000000000..b2106200e
--- /dev/null
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/LevenbergMarquardtAlgorithm.kt
@@ -0,0 +1,642 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.tensors.core
+
+import space.kscience.kmath.PerformancePitfall
+import space.kscience.kmath.nd.*
+import kotlin.math.abs
+import kotlin.math.max
+import kotlin.math.min
+import kotlin.math.pow
+
+/**
+ * Type of convergence achieved as a result of executing the Levenberg-Marquardt algorithm.
+ *
+ * InGradient: gradient convergence achieved
+ *            (max(J^T W dy) < epsilon1,
+ *            where J - Jacobi matrix (dy^/dp) for the current approximation y^,
+ *            W - weight matrix from input, dy = (y - y^(p))).
+ * InParameters: convergence in parameters achieved
+ *            (max(h_i / p_i) < epsilon2,
+ *            where h_i - offset for parameter p_i on the current iteration).
+ * InReducedChiSquare: chi-squared convergence achieved
+ *            (chi squared value divided by (m - n + 1) < epsilon2,
+ *            where n - number of parameters, m - amount of points).
+ * NoConvergence: the maximum number of iterations has been reached without reaching any convergence.
+ */
+public enum class TypeOfConvergence {
+    InGradient,
+    InParameters,
+    InReducedChiSquare,
+    NoConvergence
+}
+
+/**
+ * The data obtained as a result of the execution of the Levenberg-Marquardt algorithm.
+ *
+ *  iterations: number of completed iterations.
+ *  funcCalls: the number of evaluations of the input function during execution.
+ *  resultChiSq: chi squared value on final parameters.
+ *  resultLambda: final lambda parameter used to calculate the offset.
+ *  resultParameters: final parameters.
+ *  typeOfConvergence: type of convergence.
+ */
+public data class LMResultInfo(
+    var iterations: Int,
+    var funcCalls: Int,
+    var resultChiSq: Double,
+    var resultLambda: Double,
+    var resultParameters: MutableStructure2D<Double>,
+    var typeOfConvergence: TypeOfConvergence,
+)
+
+/**
+ * Input data for the Levenberg-Marquardt function.
+ *
+ *  func: function of n independent variables x, m parameters an example number,
+ *        rotating a vector of n values y, in which each of the y_i is calculated at its x_i with the given parameters.
+ *  startParameters: starting parameters.
+ *  independentVariables: independent variables, for each of which the real value is known.
+ *  realValues: real values obtained with given independent variables but unknown parameters.
+ *  weight: measurement error for realValues (denominator in each term of sum of weighted squared errors).
+ *  pDelta: delta when calculating the derivative with respect to parameters.
+ *  minParameters: the lower bound of parameter values.
+ *  maxParameters: upper limit of parameter values.
+ *  maxIterations: maximum allowable number of iterations.
+ *  epsilons: epsilon1 - convergence tolerance for gradient,
+ *            epsilon2 - convergence tolerance for parameters,
+ *            epsilon3 - convergence tolerance for reduced chi-square,
+ *            epsilon4 - determines acceptance of a step.
+ *  lambdas: lambda0 - starting lambda value for parameter offset count,
+ *           lambdaUp - factor for increasing lambda,
+ *           lambdaDown - factor for decreasing lambda.
+ *  updateType: 1: Levenberg-Marquardt lambda update,
+ *              2: Quadratic update,
+ *              3: Nielsen's lambda update equations.
+ *  nargin: a value that determines which options to use by default
+ *         (<5 - use weight by default, <6 - use pDelta by default, <7 - use minParameters by default,
+ *          <8 - use maxParameters by default, <9 - use updateType by default).
+ *  exampleNumber: a parameter for a function with which you can choose its behavior.
+ */
+public data class LMInput(
+    var func: (MutableStructure2D<Double>, MutableStructure2D<Double>, Int) -> (MutableStructure2D<Double>),
+    var startParameters: MutableStructure2D<Double>,
+    var independentVariables: MutableStructure2D<Double>,
+    var realValues: MutableStructure2D<Double>,
+    var weight: Double,
+    var pDelta: MutableStructure2D<Double>,
+    var minParameters: MutableStructure2D<Double>,
+    var maxParameters: MutableStructure2D<Double>,
+    var maxIterations: Int,
+    var epsilons: DoubleArray,
+    var lambdas: DoubleArray,
+    var updateType: Int,
+    var nargin: Int,
+    var exampleNumber: Int,
+)
+
+
+/**
+ * Levenberg-Marquardt optimization.
+ *
+ * An optimization method that iteratively searches for the optimal function parameters
+ * that best describe the dataset. The 'input' is the function being optimized, a set of real data
+ * (calculated with independent variables, but with an unknown set of parameters), a set of
+ * independent variables, and variables for adjusting the algorithm, described in the documentation for the LMInput class.
+ * The function returns number of completed iterations, the number of evaluations of the input function during execution,
+ * chi squared value on final parameters, final lambda parameter used to calculate the offset, final parameters
+ * and type of convergence in the 'output'.
+ *
+ * @receiver the `input`.
+ * @return the 'output'.
+ */
+public fun DoubleTensorAlgebra.levenbergMarquardt(inputData: LMInput): LMResultInfo {
+    val resultInfo = LMResultInfo(
+        0, 0, 0.0,
+        0.0, inputData.startParameters, TypeOfConvergence.NoConvergence
+    )
+
+    val settings = LMSettings(0, 0, inputData.exampleNumber)
+    settings.funcCalls = 0 // running count of function evaluations
+
+    var p = inputData.startParameters
+    val t = inputData.independentVariables
+
+    val nPar = length(p) // number of parameters
+    val nPoints = length(inputData.realValues) // number of data points
+    var pOld = zeros(ShapeND(intArrayOf(nPar, 1))).as2D() // previous set of parameters
+    var yOld = zeros(ShapeND(intArrayOf(nPoints, 1))).as2D() // previous model, y_old = y_hat(t;p_old)
+    var x2: Double   // a really big initial Chi-sq value
+    var x2Old: Double  // a really big initial Chi-sq value
+    var jacobian = zeros(ShapeND(intArrayOf(nPoints, nPar))).as2D() // Jacobian matrix
+    val dof = nPoints - nPar // statistical degrees of freedom
+
+    var weight = fromArray(ShapeND(intArrayOf(1, 1)), doubleArrayOf(inputData.weight)).as2D()
+    if (inputData.nargin < 5) {
+        weight = fromArray(
+            ShapeND(intArrayOf(1, 1)),
+            doubleArrayOf((inputData.realValues.transposed() dot inputData.realValues).as1D()[0])
+        ).as2D()
+    }
+
+    var dp = inputData.pDelta
+    if (inputData.nargin < 6) {
+        dp = fromArray(ShapeND(intArrayOf(1, 1)), doubleArrayOf(0.001)).as2D()
+    }
+
+    var minParameters = inputData.minParameters
+    if (inputData.nargin < 7) {
+        minParameters = p
+        minParameters.abs()
+        minParameters = minParameters.div(-100.0).as2D()
+    }
+
+    var maxParameters = inputData.maxParameters
+    if (inputData.nargin < 8) {
+        maxParameters = p
+        maxParameters.abs()
+        maxParameters = maxParameters.div(100.0).as2D()
+    }
+
+    var maxIterations = inputData.maxIterations
+    var epsilon1 = inputData.epsilons[0]
+    var epsilon2 = inputData.epsilons[1]
+    var epsilon3 = inputData.epsilons[2]
+    var epsilon4 = inputData.epsilons[3]
+    var lambda0 = inputData.lambdas[0]
+    var lambdaUpFac = inputData.lambdas[1]
+    var lambdaDnFac = inputData.lambdas[2]
+    var updateType = inputData.updateType
+
+    if (inputData.nargin < 9) {
+        maxIterations = 10 * nPar
+        epsilon1 = 1e-3
+        epsilon2 = 1e-3
+        epsilon3 = 1e-1
+        epsilon4 = 1e-1
+        lambda0 = 1e-2
+        lambdaUpFac = 11.0
+        lambdaDnFac = 9.0
+        updateType = 1
+    }
+
+    minParameters = makeColumn(minParameters)
+    maxParameters = makeColumn(maxParameters)
+
+    if (length(makeColumn(dp)) == 1) {
+        dp = ones(ShapeND(intArrayOf(nPar, 1))).div(1 / dp[0, 0]).as2D()
+    }
+
+    var stop = false // termination flag
+
+    if (weight.shape.component1() == 1 || variance(weight) == 0.0) { // identical weights vector
+        weight = ones(ShapeND(intArrayOf(nPoints, 1))).div(1 / abs(weight[0, 0])).as2D()
+    } else {
+        weight = makeColumn(weight)
+        weight.abs()
+    }
+
+    // initialize Jacobian with finite difference calculation
+    var lmMatxAns = lmMatx(inputData.func, t, pOld, yOld, 1, jacobian, p, inputData.realValues, weight, dp, settings)
+    var jtWJ = lmMatxAns[0]
+    var jtWdy = lmMatxAns[1]
+    x2 = lmMatxAns[2][0, 0]
+    var yHat = lmMatxAns[3]
+    jacobian = lmMatxAns[4]
+
+    if (abs(jtWdy).max() < epsilon1) {
+        stop = true
+    }
+
+    var lambda: Double
+    var nu = 1
+
+    if (updateType == 1) {
+        lambda = lambda0 // Marquardt: init'l lambda
+    } else {
+        lambda = lambda0 * (makeColumnFromDiagonal(jtWJ)).max()
+        nu = 2
+    }
+
+    x2Old = x2 // previous value of X2
+
+    var h: DoubleTensor
+
+    while (!stop && settings.iteration <= maxIterations) {
+        settings.iteration += 1
+
+        // incremental change in parameters
+        h = if (updateType == 1) { // Marquardt
+            val solve =
+                solve((jtWJ + makeMatrixWithDiagonal(makeColumnFromDiagonal(jtWJ)) / (1 / lambda)).as2D(), jtWdy)
+            solve.asDoubleTensor()
+        } else { // Quadratic and Nielsen
+            val solve = solve(jtWJ.plus(lmEye(nPar) * lambda).as2D(), jtWdy)
+            solve.asDoubleTensor()
+        }
+
+        var pTry = (p + h).as2D()  // update the [idx] elements
+        pTry = smallestElementComparison(
+            largestElementComparison(minParameters, pTry),
+            maxParameters
+        ) // apply constraints
+
+        var deltaY = inputData.realValues.minus(
+            evaluateFunction(
+                inputData.func,
+                t,
+                pTry,
+                inputData.exampleNumber
+            )
+        ) // residual error using p_try
+
+        for (i in 0 until deltaY.shape[0]) {  // floating point error; break
+            for (j in 0 until deltaY.shape[1]) {
+                if (deltaY[i, j] == Double.POSITIVE_INFINITY || deltaY[i, j] == Double.NEGATIVE_INFINITY) {
+                    stop = true
+                    break
+                }
+            }
+        }
+
+        settings.funcCalls += 1
+
+//        val tmp = deltaY.times(weight)
+        var X2Try = deltaY.as2D().transposed() dot deltaY.times(weight) // Chi-squared error criteria
+
+        val alpha = 1.0
+        if (updateType == 2) { // Quadratic
+            // One step of quadratic line update in the h direction for minimum X2
+            val alphaTensor = (jtWdy.transposed() dot h) / ((X2Try - x2) / 2.0 + 2 * (jtWdy.transposed() dot h))
+            h = h dot alphaTensor
+            pTry = (p + h).as2D() // update only [idx] elements
+            pTry = smallestElementComparison(
+                largestElementComparison(minParameters, pTry),
+                maxParameters
+            ) // apply constraints
+
+            deltaY = inputData.realValues.minus(
+                evaluateFunction(
+                    inputData.func,
+                    t,
+                    pTry,
+                    inputData.exampleNumber
+                )
+            ) // residual error using p_try
+            settings.funcCalls += 1
+
+            X2Try = deltaY.as2D().transposed() dot deltaY * weight // Chi-squared error criteria
+        }
+
+        val rho = when (updateType) { // Nielsen
+            1 -> {
+                val tmp = h.transposed()
+                    .dot((makeMatrixWithDiagonal(makeColumnFromDiagonal(jtWJ)) * lambda dot h) + jtWdy)
+                (x2 - X2Try)[0, 0] / abs(tmp.as2D())[0, 0]
+            }
+
+            else -> {
+                val tmp = h.transposed().dot((h * lambda) + jtWdy)
+                x2.minus(X2Try).as2D()[0, 0] / abs(tmp.as2D()).as2D()[0, 0]
+            }
+        }
+
+        if (rho > epsilon4) { // it IS significantly better
+            val dX2 = x2.minus(x2Old)
+            x2Old = x2
+            pOld = p.copyToTensor().as2D()
+            yOld = yHat.copyToTensor().as2D()
+            p = makeColumn(pTry) // accept p_try
+
+            lmMatxAns = lmMatx(
+                inputData.func,
+                t,
+                pOld,
+                yOld,
+                dX2.toInt(),
+                jacobian,
+                p,
+                inputData.realValues,
+                weight,
+                dp,
+                settings
+            )
+            // decrease lambda ==> Gauss-Newton method
+            jtWJ = lmMatxAns[0]
+            jtWdy = lmMatxAns[1]
+            x2 = lmMatxAns[2][0, 0]
+            yHat = lmMatxAns[3]
+            jacobian = lmMatxAns[4]
+
+            lambda = when (updateType) {
+                1 -> { // Levenberg
+                    max(lambda / lambdaDnFac, 1e-7);
+                }
+
+                2 -> { // Quadratic
+                    max(lambda / (1 + alpha), 1e-7);
+                }
+
+                else -> { // Nielsen
+                    nu = 2
+                    lambda * max(1.0 / 3, 1 - (2 * rho - 1).pow(3))
+                }
+            }
+        } else { // it IS NOT better
+            x2 = x2Old // do not accept p_try
+            if (settings.iteration % (2 * nPar) == 0) { // rank-1 update of Jacobian
+                lmMatxAns =
+                    lmMatx(inputData.func, t, pOld, yOld, -1, jacobian, p, inputData.realValues, weight, dp, settings)
+                jtWJ = lmMatxAns[0]
+                jtWdy = lmMatxAns[1]
+                yHat = lmMatxAns[3]
+                jacobian = lmMatxAns[4]
+            }
+
+            // increase lambda  ==> gradient descent method
+            lambda = when (updateType) {
+                1 -> { // Levenberg
+                    min(lambda * lambdaUpFac, 1e7)
+                }
+
+                2 -> { // Quadratic
+                    lambda + abs(((X2Try.as2D()[0, 0] - x2) / 2) / alpha)
+                }
+
+                else -> { // Nielsen
+                    nu *= 2
+                    lambda * (nu / 2)
+                }
+            }
+        }
+
+        val chiSq = x2 / dof
+        resultInfo.iterations = settings.iteration
+        resultInfo.funcCalls = settings.funcCalls
+        resultInfo.resultChiSq = chiSq
+        resultInfo.resultLambda = lambda
+        resultInfo.resultParameters = p
+
+
+        if (abs(jtWdy).max() < epsilon1 && settings.iteration > 2) {
+            resultInfo.typeOfConvergence = TypeOfConvergence.InGradient
+            stop = true
+        }
+        if ((abs(h.as2D()) / (abs(p) + 1e-12)).max() < epsilon2 && settings.iteration > 2) {
+            resultInfo.typeOfConvergence = TypeOfConvergence.InParameters
+            stop = true
+        }
+        if (x2 / dof < epsilon3 && settings.iteration > 2) {
+            resultInfo.typeOfConvergence = TypeOfConvergence.InReducedChiSquare
+            stop = true
+        }
+        if (settings.iteration == maxIterations) {
+            resultInfo.typeOfConvergence = TypeOfConvergence.NoConvergence
+            stop = true
+        }
+    }
+    return resultInfo
+}
+
+private data class LMSettings(
+    var iteration: Int,
+    var funcCalls: Int,
+    var exampleNumber: Int,
+)
+
+/* matrix -> column of all elements */
+private fun makeColumn(tensor: MutableStructure2D<Double>): MutableStructure2D<Double> {
+    val shape = intArrayOf(tensor.shape.component1() * tensor.shape.component2(), 1)
+    val buffer = DoubleArray(tensor.shape.component1() * tensor.shape.component2())
+    for (i in 0 until tensor.shape.component1()) {
+        for (j in 0 until tensor.shape.component2()) {
+            buffer[i * tensor.shape.component2() + j] = tensor[i, j]
+        }
+    }
+    return BroadcastDoubleTensorAlgebra.fromArray(ShapeND(shape), buffer).as2D()
+}
+
+/* column length */
+private fun length(column: MutableStructure2D<Double>): Int {
+    return column.shape.component1()
+}
+
+private fun MutableStructure2D<Double>.abs() {
+    for (i in 0 until this.shape[0]) {
+        for (j in 0 until this.shape[1]) {
+            this[i, j] = abs(this[i, j])
+        }
+    }
+}
+
+private fun abs(input: MutableStructure2D<Double>): MutableStructure2D<Double> {
+    val tensor = BroadcastDoubleTensorAlgebra.ones(
+        ShapeND(
+            intArrayOf(
+                input.shape.component1(),
+                input.shape.component2()
+            )
+        )
+    ).as2D()
+    for (i in 0 until tensor.shape.component1()) {
+        for (j in 0 until tensor.shape.component2()) {
+            tensor[i, j] = abs(input[i, j])
+        }
+    }
+    return tensor
+}
+
+private fun makeColumnFromDiagonal(input: MutableStructure2D<Double>): MutableStructure2D<Double> {
+    val tensor = BroadcastDoubleTensorAlgebra.ones(ShapeND(intArrayOf(input.shape.component1(), 1))).as2D()
+    for (i in 0 until tensor.shape.component1()) {
+        tensor[i, 0] = input[i, i]
+    }
+    return tensor
+}
+
+private fun makeMatrixWithDiagonal(column: MutableStructure2D<Double>): MutableStructure2D<Double> {
+    val size = column.shape.component1()
+    val tensor = BroadcastDoubleTensorAlgebra.zeros(ShapeND(intArrayOf(size, size))).as2D()
+    for (i in 0 until size) {
+        tensor[i, i] = column[i, 0]
+    }
+    return tensor
+}
+
+private fun lmEye(size: Int): MutableStructure2D<Double> {
+    val column = BroadcastDoubleTensorAlgebra.ones(ShapeND(intArrayOf(size, 1))).as2D()
+    return makeMatrixWithDiagonal(column)
+}
+
+private fun largestElementComparison(
+    a: MutableStructure2D<Double>,
+    b: MutableStructure2D<Double>,
+): MutableStructure2D<Double> {
+    val aSizeX = a.shape.component1()
+    val aSizeY = a.shape.component2()
+    val bSizeX = b.shape.component1()
+    val bSizeY = b.shape.component2()
+    val tensor =
+        BroadcastDoubleTensorAlgebra.zeros(ShapeND(intArrayOf(max(aSizeX, bSizeX), max(aSizeY, bSizeY)))).as2D()
+    for (i in 0 until tensor.shape.component1()) {
+        for (j in 0 until tensor.shape.component2()) {
+            if (i < aSizeX && i < bSizeX && j < aSizeY && j < bSizeY) {
+                tensor[i, j] = max(a[i, j], b[i, j])
+            } else if (i < aSizeX && j < aSizeY) {
+                tensor[i, j] = a[i, j]
+            } else {
+                tensor[i, j] = b[i, j]
+            }
+        }
+    }
+    return tensor
+}
+
+private fun smallestElementComparison(
+    a: MutableStructure2D<Double>,
+    b: MutableStructure2D<Double>,
+): MutableStructure2D<Double> {
+    val aSizeX = a.shape.component1()
+    val aSizeY = a.shape.component2()
+    val bSizeX = b.shape.component1()
+    val bSizeY = b.shape.component2()
+    val tensor =
+        BroadcastDoubleTensorAlgebra.zeros(ShapeND(intArrayOf(max(aSizeX, bSizeX), max(aSizeY, bSizeY)))).as2D()
+    for (i in 0 until tensor.shape.component1()) {
+        for (j in 0 until tensor.shape.component2()) {
+            if (i < aSizeX && i < bSizeX && j < aSizeY && j < bSizeY) {
+                tensor[i, j] = min(a[i, j], b[i, j])
+            } else if (i < aSizeX && j < aSizeY) {
+                tensor[i, j] = a[i, j]
+            } else {
+                tensor[i, j] = b[i, j]
+            }
+        }
+    }
+    return tensor
+}
+
+private fun getZeroIndices(
+    column: MutableStructure2D<Double>,
+    epsilon: Double = 0.000001,
+): MutableStructure2D<Double>? {
+    var idx = emptyArray<Double>()
+    for (i in 0 until column.shape.component1()) {
+        if (abs(column[i, 0]) > epsilon) {
+            idx += (i + 1.0)
+        }
+    }
+    if (idx.isNotEmpty()) {
+        return BroadcastDoubleTensorAlgebra.fromArray(ShapeND(intArrayOf(idx.size, 1)), idx.toDoubleArray()).as2D()
+    }
+    return null
+}
+
+private fun evaluateFunction(
+    func: (MutableStructure2D<Double>, MutableStructure2D<Double>, Int) -> MutableStructure2D<Double>,
+    t: MutableStructure2D<Double>, p: MutableStructure2D<Double>, exampleNumber: Int,
+)
+        : MutableStructure2D<Double> {
+    return func(t, p, exampleNumber)
+}
+
+private fun lmMatx(
+    func: (MutableStructure2D<Double>, MutableStructure2D<Double>, Int) -> MutableStructure2D<Double>,
+    t: MutableStructure2D<Double>,
+    pOld: MutableStructure2D<Double>,
+    yOld: MutableStructure2D<Double>,
+    dX2: Int,
+    JInput: MutableStructure2D<Double>,
+    p: MutableStructure2D<Double>,
+    yDat: MutableStructure2D<Double>,
+    weight: MutableStructure2D<Double>,
+    dp: MutableStructure2D<Double>,
+    settings: LMSettings,
+): Array<MutableStructure2D<Double>> = with(DoubleTensorAlgebra) {
+    // default: dp = 0.001
+    val Npar = length(p) // number of parameters
+
+    val yHat = evaluateFunction(func, t, p, settings.exampleNumber) // evaluate model using parameters 'p'
+    settings.funcCalls += 1
+
+    var J = JInput
+
+    J = if (settings.iteration % (2 * Npar) == 0 || dX2 > 0) {
+        lmFdJ(func, t, p, yHat, dp, settings).as2D() // finite difference
+    } else {
+        lmBroydenJ(pOld, yOld, J, p, yHat).as2D() // rank-1 update
+    }
+
+    val deltaY = yDat.minus(yHat)
+
+    val chiSq = deltaY.transposed().dot(deltaY.times(weight)).as2D()
+    val JtWJ =
+        (J.transposed() dot J * (weight dot ones(ShapeND(intArrayOf(1, Npar))))).as2D()
+    val JtWdy = (J.transposed() dot weight * deltaY).as2D()
+
+    return arrayOf(JtWJ, JtWdy, chiSq, yHat, J)
+}
+
+private fun lmBroydenJ(
+    pOld: MutableStructure2D<Double>, yOld: MutableStructure2D<Double>, JInput: MutableStructure2D<Double>,
+    p: MutableStructure2D<Double>, y: MutableStructure2D<Double>,
+): MutableStructure2D<Double> = with(DoubleTensorAlgebra) {
+    var J = JInput.copyToTensor()
+
+    val h = p.minus(pOld)
+    val increase = ((y - yOld - (J dot h)) dot h.transposed()) / (h.transposed() dot h)[0, 0]
+    J = J.plus(increase)
+
+    return J.as2D()
+}
+
+@OptIn(PerformancePitfall::class)
+private fun lmFdJ(
+    func: (MutableStructure2D<Double>, MutableStructure2D<Double>, exampleNumber: Int) -> MutableStructure2D<Double>,
+    t: MutableStructure2D<Double>,
+    p: MutableStructure2D<Double>,
+    y: MutableStructure2D<Double>,
+    dp: MutableStructure2D<Double>,
+    settings: LMSettings,
+): MutableStructure2D<Double> = with(DoubleTensorAlgebra) {
+    // default: dp = 0.001 * ones(1,n)
+
+    val m = length(y) // number of data points
+    val n = length(p) // number of parameters
+
+    val ps = p.copyToTensor()
+    val J = zero(m, n)  // initialize Jacobian to Zero
+    val del = zero(n, 1)
+
+    for (j in 0 until n) {
+
+        del[j, 0] = dp[j, 0] * (1 + abs(p[j, 0])) // parameter perturbation
+        p[j, 0] = ps[j, 0] + del[j, 0] // perturb parameter p(j)
+
+        val epsilon = 0.0000001
+        if (abs(del[j, 0]) > epsilon) {
+            val y1 = evaluateFunction(func, t, p, settings.exampleNumber)
+            settings.funcCalls += 1
+
+            if (dp[j, 0] < 0) { // backwards difference
+                for (i in 0 until J.shape.first()) {
+                    J[i, j] = (y1 - y)[i, 0] / del[j, 0]
+                }
+            } else {
+                // Do tests for it
+                p[j, 0] = ps[j, 0] - del[j, 0] // central difference, additional func call
+                for (i in 0 until J.shape.first()) {
+                    J[i, j] = (y1 - evaluateFunction(func, t, p, settings.exampleNumber))[i, 0] / (2 * del[j, 0])
+                }
+                settings.funcCalls += 1
+            }
+        }
+
+        p[j, 0] = ps[j, 0]
+    }
+
+    return J.as2D()
+}
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt
index 1e87e6620..df43a7e60 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -116,6 +116,7 @@ internal fun broadcastOuterTensors(vararg tensors: DoubleTensor): List<DoubleTen
 
             for (linearIndex in 0 until n) {
                 val totalMultiIndex = outerTensor.indices.index(linearIndex)
+
                 @OptIn(UnsafeKMathAPI::class)
                 var curMultiIndex = tensor.shape.slice(0..tensor.shape.size - 3).asArray()
                 curMultiIndex = IntArray(totalMultiIndex.size - curMultiIndex.size) { 1 } + curMultiIndex
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt
index f384ed462..1a0aa29d1 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/doubleTensorHelpers.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/doubleTensorHelpers.kt
index a293c8da3..4750dbea2 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/doubleTensorHelpers.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/doubleTensorHelpers.kt
@@ -1,12 +1,12 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.tensors.core.internal
 
 import space.kscience.kmath.nd.*
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import space.kscience.kmath.structures.asBuffer
 import space.kscience.kmath.structures.indices
 import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.eye
@@ -22,13 +22,13 @@ import kotlin.math.sqrt
 internal fun MutableStructure2D<Double>.jacobiHelper(
     maxIteration: Int,
     epsilon: Double,
-): Pair<DoubleBuffer, Structure2D<Double>> {
+): Pair<Float64Buffer, Structure2D<Double>> {
     val n = rowNum
     val A_ = copyToTensor()
     val V = eye(n)
-    val D = DoubleBuffer(n) { get(it, it) }
-    val B = DoubleBuffer(n) { get(it, it) }
-    val Z = DoubleBuffer(n) { 0.0 }
+    val D = Float64Buffer(n) { get(it, it) }
+    val B = Float64Buffer(n) { get(it, it) }
+    val Z = Float64Buffer(n) { 0.0 }
 
     // assume that buffered tensor is square matrix
     operator fun DoubleTensor.get(i: Int, j: Int): Double {
@@ -59,8 +59,8 @@ internal fun MutableStructure2D<Double>.jacobiHelper(
     fun jacobiIteration(
         a: DoubleTensor,
         v: DoubleTensor,
-        d: DoubleBuffer,
-        z: DoubleBuffer,
+        d: Float64Buffer,
+        z: Float64Buffer,
     ) {
         for (ip in 0 until n - 1) {
             for (iq in ip + 1 until n) {
@@ -108,9 +108,9 @@ internal fun MutableStructure2D<Double>.jacobiHelper(
     }
 
     fun updateDiagonal(
-        d: DoubleBuffer,
-        z: DoubleBuffer,
-        b: DoubleBuffer,
+        d: Float64Buffer,
+        z: Float64Buffer,
+        b: Float64Buffer,
     ) {
         for (ip in 0 until d.size) {
             b[ip] += z[ip]
@@ -137,7 +137,7 @@ internal fun MutableStructure2D<Double>.jacobiHelper(
 /**
  * Concatenate a list of arrays
  */
-internal fun List<OffsetDoubleBuffer>.concat(): DoubleBuffer {
+internal fun List<OffsetDoubleBuffer>.concat(): Float64Buffer {
     val array = DoubleArray(sumOf { it.size })
     var pointer = 0
     while (pointer < array.size) {
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/intTensorHelpers.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/intTensorHelpers.kt
index 35f0bf324..a28f73799 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/intTensorHelpers.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/intTensorHelpers.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -9,7 +9,7 @@ import space.kscience.kmath.nd.ShapeND
 import space.kscience.kmath.nd.first
 import space.kscience.kmath.nd.last
 import space.kscience.kmath.operations.asSequence
-import space.kscience.kmath.structures.IntBuffer
+import space.kscience.kmath.structures.Int32Buffer
 import space.kscience.kmath.structures.VirtualBuffer
 import space.kscience.kmath.structures.asBuffer
 import space.kscience.kmath.structures.indices
@@ -19,7 +19,7 @@ import space.kscience.kmath.tensors.core.OffsetIntBuffer
 /**
  * Concatenate a list of arrays
  */
-internal fun List<OffsetIntBuffer>.concat(): IntBuffer {
+internal fun List<OffsetIntBuffer>.concat(): Int32Buffer {
     val array = IntArray(sumOf { it.size })
     var pointer = 0
     while (pointer < array.size) {
@@ -51,7 +51,7 @@ internal fun IntTensor.vectorSequence(): Sequence<IntTensor> = vectors().asSeque
 
 
 internal val IntTensor.matrices: VirtualBuffer<IntTensor>
-    get(){
+    get() {
         val n = shape.size
         check(n >= 2) { "Expected tensor with 2 or more dimensions, got size $n" }
         val matrixOffset = shape[n - 1] * shape[n - 2]
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt
index cf3697e76..239d1dd18 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -7,12 +7,13 @@ package space.kscience.kmath.tensors.core.internal
 
 import space.kscience.kmath.nd.*
 import space.kscience.kmath.operations.invoke
-import space.kscience.kmath.structures.DoubleBuffer
-import space.kscience.kmath.structures.IntBuffer
+import space.kscience.kmath.structures.Float64Buffer
+import space.kscience.kmath.structures.Int32Buffer
 import space.kscience.kmath.structures.asBuffer
 import space.kscience.kmath.structures.indices
 import space.kscience.kmath.tensors.core.*
 import kotlin.math.abs
+import kotlin.math.max
 import kotlin.math.min
 import kotlin.math.sqrt
 
@@ -96,7 +97,7 @@ internal fun <T> StructureND<T>.setUpPivots(): IntTensor {
 
     return IntTensor(
         ShapeND(pivotsShape),
-        IntBuffer(pivotsShape.reduce(Int::times)) { 0 }
+        Int32Buffer(pivotsShape.reduce(Int::times)) { 0 }
     )
 }
 
@@ -240,10 +241,10 @@ internal fun DoubleTensorAlgebra.svd1d(a: DoubleTensor, epsilon: Double = 1e-10)
     val b: DoubleTensor
     if (n > m) {
         b = a.transposed(0, 1).dot(a)
-        v = DoubleTensor(ShapeND(m), DoubleBuffer.randomUnitVector(m, 0))
+        v = DoubleTensor(ShapeND(m), Float64Buffer.randomUnitVector(m, 0))
     } else {
         b = a.dot(a.transposed(0, 1))
-        v = DoubleTensor(ShapeND(n), DoubleBuffer.randomUnitVector(n, 0))
+        v = DoubleTensor(ShapeND(n), Float64Buffer.randomUnitVector(n, 0))
     }
 
     var lastV: DoubleTensor
@@ -308,3 +309,295 @@ internal fun DoubleTensorAlgebra.svdHelper(
         matrixV.source[i] = vBuffer[i]
     }
 }
+
+internal fun MutableStructure2D<Double>.svdGolubKahanHelper(
+    u: MutableStructure2D<Double>, w: BufferedTensor<Double>,
+    v: MutableStructure2D<Double>, iterations: Int, epsilon: Double,
+) {
+    fun pythag(a: Double, b: Double): Double {
+        val at: Double = abs(a)
+        val bt: Double = abs(b)
+        val ct: Double
+        val result: Double
+        if (at > bt) {
+            ct = bt / at
+            result = at * sqrt(1.0 + ct * ct)
+        } else if (bt > 0.0) {
+            ct = at / bt
+            result = bt * sqrt(1.0 + ct * ct)
+        } else result = 0.0
+        return result
+    }
+
+
+    val shape = this.shape
+    val m = shape.component1()
+    val n = shape.component2()
+    var f: Double
+    val rv1 = DoubleArray(n)
+    var s: Double
+    var scale = 0.0
+    var anorm = 0.0
+    var g = 0.0
+    var l = 0
+
+    val wStart = 0
+    val wBuffer = w.source
+
+    for (i in 0 until n) {
+        /* left-hand reduction */
+        l = i + 1
+        rv1[i] = scale * g
+        g = 0.0
+        s = 0.0
+        scale = 0.0
+        if (i < m) {
+            for (k in i until m) {
+                scale += abs(this[k, i]);
+            }
+            if (abs(scale) > epsilon) {
+                for (k in i until m) {
+                    this[k, i] = (this[k, i] / scale)
+                    s += this[k, i] * this[k, i]
+                }
+                f = this[i, i]
+                g = if (f >= 0) {
+                    -abs(sqrt(s))
+                } else {
+                    abs(sqrt(s))
+                }
+                val h = f * g - s
+                this[i, i] = f - g
+                if (i != n - 1) {
+                    for (j in l until n) {
+                        s = 0.0
+                        for (k in i until m) {
+                            s += this[k, i] * this[k, j]
+                        }
+                        f = s / h
+                        for (k in i until m) {
+                            this[k, j] += f * this[k, i]
+                        }
+                    }
+                }
+                for (k in i until m) {
+                    this[k, i] = this[k, i] * scale
+                }
+            }
+        }
+
+        wBuffer[wStart + i] = scale * g
+        /* right-hand reduction */
+        g = 0.0
+        s = 0.0
+        scale = 0.0
+        if (i < m && i != n - 1) {
+            for (k in l until n) {
+                scale += abs(this[i, k])
+            }
+            if (abs(scale) > epsilon) {
+                for (k in l until n) {
+                    this[i, k] = this[i, k] / scale
+                    s += this[i, k] * this[i, k]
+                }
+                f = this[i, l]
+                g = if (f >= 0) {
+                    -abs(sqrt(s))
+                } else {
+                    abs(sqrt(s))
+                }
+                val h = f * g - s
+                this[i, l] = f - g
+                for (k in l until n) {
+                    rv1[k] = this[i, k] / h
+                }
+                if (i != m - 1) {
+                    for (j in l until m) {
+                        s = 0.0
+                        for (k in l until n) {
+                            s += this[j, k] * this[i, k]
+                        }
+                        for (k in l until n) {
+                            this[j, k] += s * rv1[k]
+                        }
+                    }
+                }
+                for (k in l until n) {
+                    this[i, k] = this[i, k] * scale
+                }
+            }
+        }
+        anorm = max(anorm, (abs(wBuffer[wStart + i]) + abs(rv1[i])));
+    }
+
+    for (i in n - 1 downTo 0) {
+        if (i < n - 1) {
+            if (abs(g) > epsilon) {
+                for (j in l until n) {
+                    v[j, i] = (this[i, j] / this[i, l]) / g
+                }
+                for (j in l until n) {
+                    s = 0.0
+                    for (k in l until n)
+                        s += this[i, k] * v[k, j]
+                    for (k in l until n)
+                        v[k, j] += s * v[k, i]
+                }
+            }
+            for (j in l until n) {
+                v[i, j] = 0.0
+                v[j, i] = 0.0
+            }
+        }
+        v[i, i] = 1.0
+        g = rv1[i]
+        l = i
+    }
+
+    for (i in min(n, m) - 1 downTo 0) {
+        l = i + 1
+        g = wBuffer[wStart + i]
+        for (j in l until n) {
+            this[i, j] = 0.0
+        }
+        if (abs(g) > epsilon) {
+            g = 1.0 / g
+            for (j in l until n) {
+                s = 0.0
+                for (k in l until m) {
+                    s += this[k, i] * this[k, j]
+                }
+                f = (s / this[i, i]) * g
+                for (k in i until m) {
+                    this[k, j] += f * this[k, i]
+                }
+            }
+            for (j in i until m) {
+                this[j, i] *= g
+            }
+        } else {
+            for (j in i until m) {
+                this[j, i] = 0.0
+            }
+        }
+        this[i, i] += 1.0
+    }
+
+    var flag: Int
+    var nm = 0
+    var c: Double
+    var h: Double
+    var y: Double
+    var z: Double
+    var x: Double
+    for (k in n - 1 downTo 0) {
+        for (its in 1 until iterations) {
+            flag = 1
+            for (newl in k downTo 0) {
+                nm = newl - 1
+                if (abs(rv1[newl]) + anorm == anorm) {
+                    flag = 0
+                    l = newl
+                    break
+                }
+                if (abs(wBuffer[wStart + nm]) + anorm == anorm) {
+                    l = newl
+                    break
+                }
+            }
+
+            if (flag != 0) {
+                c = 0.0
+                s = 1.0
+                for (i in l until k + 1) {
+                    f = s * rv1[i]
+                    rv1[i] = c * rv1[i]
+                    if (abs(f) + anorm == anorm) {
+                        break
+                    }
+                    g = wBuffer[wStart + i]
+                    h = pythag(f, g)
+                    wBuffer[wStart + i] = h
+                    h = 1.0 / h
+                    c = g * h
+                    s = (-f) * h
+                    for (j in 0 until m) {
+                        y = this[j, nm]
+                        z = this[j, i]
+                        this[j, nm] = y * c + z * s
+                        this[j, i] = z * c - y * s
+                    }
+                }
+            }
+
+            z = wBuffer[wStart + k]
+            if (l == k) {
+                if (z < 0.0) {
+                    wBuffer[wStart + k] = -z
+                    for (j in 0 until n)
+                        v[j, k] = -v[j, k]
+                }
+                break
+            }
+
+            x = wBuffer[wStart + l]
+            nm = k - 1
+            y = wBuffer[wStart + nm]
+            g = rv1[nm]
+            h = rv1[k]
+            f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2.0 * h * y)
+            g = pythag(f, 1.0)
+            f = ((x - z) * (x + z) + h * ((y / (f + if (f >= 0.0) abs(g) else -abs(g))) - h)) / x
+            c = 1.0
+            s = 1.0
+
+            var i: Int
+            for (j in l until nm + 1) {
+                i = j + 1
+                g = rv1[i]
+                y = wBuffer[wStart + i]
+                h = s * g
+                g *= c
+                z = pythag(f, h)
+                rv1[j] = z
+                c = f / z
+                s = h / z
+                f = x * c + g * s
+                g = g * c - x * s
+                h = y * s
+                y *= c
+
+                for (jj in 0 until n) {
+                    x = v[jj, j];
+                    z = v[jj, i];
+                    v[jj, j] = x * c + z * s;
+                    v[jj, i] = z * c - x * s;
+                }
+                z = pythag(f, h)
+                wBuffer[wStart + j] = z
+                if (abs(z) > epsilon) {
+                    z = 1.0 / z
+                    c = f * z
+                    s = h * z
+                }
+                f = c * g + s * y
+                x = c * y - s * g
+                for (jj in 0 until m) {
+                    y = this[jj, j]
+                    z = this[jj, i]
+                    this[jj, j] = y * c + z * s
+                    this[jj, i] = z * c - y * s
+                }
+            }
+            rv1[l] = 0.0
+            rv1[k] = f
+            wBuffer[wStart + k] = x
+        }
+    }
+
+    for (i in 0 until n) {
+        for (j in 0 until m) {
+            u[j, i] = this[j, i]
+        }
+    }
+}
\ No newline at end of file
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt
index 2709ac474..4dc6b8517 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,22 +8,22 @@ package space.kscience.kmath.tensors.core.internal
 import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.nd.asList
 import space.kscience.kmath.nd.last
-import space.kscience.kmath.operations.DoubleBufferOps.Companion.map
+import space.kscience.kmath.operations.Float64BufferOps.Companion.map
 import space.kscience.kmath.random.RandomGenerator
 import space.kscience.kmath.samplers.GaussianSampler
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import space.kscience.kmath.tensors.core.BufferedTensor
 import space.kscience.kmath.tensors.core.DoubleTensor
 import kotlin.math.*
 
-internal fun DoubleBuffer.Companion.randomNormals(n: Int, seed: Long): DoubleBuffer {
+internal fun Float64Buffer.Companion.randomNormals(n: Int, seed: Long): Float64Buffer {
     val distribution = GaussianSampler(0.0, 1.0)
     val generator = RandomGenerator.default(seed)
     return distribution.sample(generator).nextBufferBlocking(n)
 }
 
-internal fun DoubleBuffer.Companion.randomUnitVector(n: Int, seed: Long): DoubleBuffer {
-    val unnorm: DoubleBuffer = randomNormals(n, seed)
+internal fun Float64Buffer.Companion.randomUnitVector(n: Int, seed: Long): Float64Buffer {
+    val unnorm: Float64Buffer = randomNormals(n, seed)
     val norm = sqrt(unnorm.array.sumOf { it * it })
     return unnorm.map { it / norm }
 }
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt
index e2b7c23e6..841c51244 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorOps.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorOps.kt
index e5dc55f68..9b31e5694 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorOps.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorOps.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,7 +8,7 @@ package space.kscience.kmath.tensors.core
 import space.kscience.kmath.nd.*
 import space.kscience.kmath.operations.covariance
 import space.kscience.kmath.structures.Buffer
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import space.kscience.kmath.tensors.api.Tensor
 import space.kscience.kmath.tensors.core.internal.*
 import kotlin.math.min
@@ -24,7 +24,7 @@ import kotlin.math.sign
  * with `0.0` mean and `1.0` standard deviation.
  */
 public fun DoubleTensorAlgebra.randomNormal(shape: ShapeND, seed: Long = 0): DoubleTensor =
-    fromBuffer(shape, DoubleBuffer.randomNormals(shape.linearSize, seed))
+    fromBuffer(shape, Float64Buffer.randomNormals(shape.linearSize, seed))
 
 /**
  * Returns a tensor with the same shape as `input` of random numbers drawn from normal distributions
@@ -36,7 +36,7 @@ public fun DoubleTensorAlgebra.randomNormal(shape: ShapeND, seed: Long = 0): Dou
  * with `0.0` mean and `1.0` standard deviation.
  */
 public fun DoubleTensorAlgebra.randomNormalLike(structure: WithShape, seed: Long = 0): DoubleTensor =
-    DoubleTensor(structure.shape, DoubleBuffer.randomNormals(structure.shape.linearSize, seed))
+    DoubleTensor(structure.shape, Float64Buffer.randomNormals(structure.shape.linearSize, seed))
 
 /**
  * Concatenates a sequence of tensors with equal shapes along the first dimension.
@@ -212,6 +212,38 @@ public fun DoubleTensorAlgebra.svd(
     return Triple(uTensor.transposed(), sTensor, vTensor.transposed())
 }
 
+public fun DoubleTensorAlgebra.svdGolubKahan(
+    structureND: StructureND<Double>,
+    iterations: Int = 30, epsilon: Double = 1e-10,
+): Triple<DoubleTensor, DoubleTensor, DoubleTensor> {
+    val size = structureND.dimension
+    val commonShape = structureND.shape.slice(0 until size - 2)
+    val (n, m) = structureND.shape.slice(size - 2 until size)
+    val uTensor = zeros(commonShape + intArrayOf(n, m))
+    val sTensor = zeros(commonShape + intArrayOf(m))
+    val vTensor = zeros(commonShape + intArrayOf(m, m))
+
+    val matrices = structureND.asDoubleTensor().matrices
+    val uTensors = uTensor.matrices
+    val sTensorVectors = sTensor.vectors
+    val vTensors = vTensor.matrices
+
+    for (index in matrices.indices) {
+        val matrix = matrices[index]
+        val matrixSize = matrix.shape.linearSize
+        val curMatrix = DoubleTensor(
+            matrix.shape,
+            matrix.source.view(0, matrixSize).copy()
+        )
+        curMatrix.as2D().svdGolubKahanHelper(
+            uTensors[index].as2D(), sTensorVectors[index], vTensors[index].as2D(),
+            iterations, epsilon
+        )
+    }
+
+    return Triple(uTensor, sTensor, vTensor)
+}
+
 /**
  * Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices,
  * represented by a pair `eigenvalues to eigenvectors`.
@@ -306,7 +338,7 @@ public fun DoubleTensorAlgebra.detLU(structureND: StructureND<Double>, epsilon:
         set(n - 2, 1)
     })
 
-    val resBuffer = DoubleBuffer(detTensorShape.linearSize) { 0.0 }
+    val resBuffer = Float64Buffer(detTensorShape.linearSize) { 0.0 }
 
     val detTensor = DoubleTensor(
         detTensorShape,
@@ -359,7 +391,7 @@ public fun DoubleTensorAlgebra.covariance(vectors: List<Buffer<Double>>): Double
     check(vectors.all { it.size == m }) { "Vectors must have same shapes" }
     val resTensor = DoubleTensor(
         ShapeND(n, n),
-        DoubleBuffer(n * n) { 0.0 }
+        Float64Buffer(n * n) { 0.0 }
     )
     for (i in 0 until n) {
         for (j in 0 until n) {
diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorTransform.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorTransform.kt
index 3b0d15400..6490ecdb9 100644
--- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorTransform.kt
+++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorTransform.kt
@@ -1,12 +1,12 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.tensors.core
 
 import space.kscience.kmath.nd.*
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import space.kscience.kmath.structures.asBuffer
 import space.kscience.kmath.tensors.api.Tensor
 
@@ -16,8 +16,8 @@ import space.kscience.kmath.tensors.api.Tensor
  */
 public fun StructureND<Double>.copyToTensor(): DoubleTensor = if (this is DoubleTensor) {
     DoubleTensor(shape, source.copy())
-} else if (this is DoubleBufferND && indices is RowStrides) {
-    DoubleTensor(shape, buffer.copy())
+} else if (this is Float64BufferND && indices is RowStrides) {
+    DoubleTensor(shape, buffer.array.copyOf().asBuffer())
 } else {
     DoubleTensor(
         shape,
@@ -29,7 +29,7 @@ public fun StructureND<Int>.toDoubleTensor(): DoubleTensor {
     return if (this is IntTensor) {
         DoubleTensor(
             shape,
-            DoubleBuffer(linearSize) { source[it].toDouble() }
+            Float64Buffer(linearSize) { source[it].toDouble() }
         )
     } else {
         val tensor = DoubleTensorAlgebra.zeroesLike(this)
@@ -45,7 +45,7 @@ public fun StructureND<Int>.toDoubleTensor(): DoubleTensor {
  */
 public fun StructureND<Double>.asDoubleTensor(): DoubleTensor = if (this is DoubleTensor) {
     this
-} else if (this is DoubleBufferND && indices is RowStrides) {
+} else if (this is Float64BufferND && indices is RowStrides) {
     DoubleTensor(shape, buffer)
 } else {
     copyToTensor()
diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt
index 73aed8a7b..f930cf94c 100644
--- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt
+++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt
index e4c2c40ea..7fd011986 100644
--- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt
+++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt
index cbd7b9887..1c500af8b 100644
--- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt
+++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt
index 811fc1117..92d997468 100644
--- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt
+++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -8,7 +8,7 @@ package space.kscience.kmath.tensors.core
 import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.nd.*
 import space.kscience.kmath.operations.invoke
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import space.kscience.kmath.structures.toDoubleArray
 import space.kscience.kmath.tensors.core.internal.matrixSequence
 import space.kscience.kmath.testutils.assertBufferEquals
@@ -65,10 +65,10 @@ internal class TestDoubleTensor {
     fun testNoBufferProtocol() {
 
         // create buffer
-        val doubleArray = DoubleBuffer(1.0, 2.0, 3.0)
+        val doubleArray = Float64Buffer(1.0, 2.0, 3.0)
 
         // create ND buffers, no data is copied
-        val ndArray: MutableBufferND<Double> = DoubleBufferND(ColumnStrides(ShapeND(3)), doubleArray)
+        val ndArray: MutableBufferND<Double> = Float64BufferND(ColumnStrides(ShapeND(3)), doubleArray)
 
         // map to tensors
         val tensorArray = ndArray.asDoubleTensor() // Data is copied because of strides change.
@@ -92,16 +92,16 @@ internal class TestDoubleTensor {
 
     @Test
     fun test2D() = with(DoubleTensorAlgebra) {
-        val tensor: DoubleTensor = structureND(ShapeND(3, 3)) { (i, j) -> (i - j).toDouble() }
+        val tensor: DoubleTensor = mutableStructureND(ShapeND(3, 3)) { (i, j) -> (i - j).toDouble() }
         //println(tensor.toPrettyString())
         val tensor2d = tensor.asDoubleTensor2D()
-        assertBufferEquals(DoubleBuffer(1.0, 0.0, -1.0), tensor2d.rows[1])
-        assertBufferEquals(DoubleBuffer(-2.0, -1.0, 0.0), tensor2d.columns[2])
+        assertBufferEquals(Float64Buffer(1.0, 0.0, -1.0), tensor2d.rows[1])
+        assertBufferEquals(Float64Buffer(-2.0, -1.0, 0.0), tensor2d.columns[2])
     }
 
     @Test
     fun testMatrixIteration() = with(DoubleTensorAlgebra) {
-        val tensor = structureND(ShapeND(3, 3, 3, 3)) { index -> index.sum().toDouble() }
+        val tensor = mutableStructureND(ShapeND(3, 3, 3, 3)) { index -> index.sum().toDouble() }
         tensor.forEachMatrix { index, matrix ->
             println(index.joinToString { it.toString() })
             println(matrix)
diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt
index cae01bed8..4f58846aa 100644
--- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt
+++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt
@@ -1,14 +1,12 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.tensors.core
 
 
-import space.kscience.kmath.nd.ShapeND
-import space.kscience.kmath.nd.contentEquals
-import space.kscience.kmath.nd.get
+import space.kscience.kmath.nd.*
 import space.kscience.kmath.operations.invoke
 import space.kscience.kmath.testutils.assertBufferEquals
 import kotlin.test.Test
diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/offsetBufferEquality.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/offsetBufferEquality.kt
index e9fc7fb9c..38c51d66e 100644
--- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/offsetBufferEquality.kt
+++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/offsetBufferEquality.kt
@@ -1,18 +1,18 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.tensors.core
 
 import space.kscience.kmath.structures.Buffer
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import space.kscience.kmath.structures.indices
 import kotlin.jvm.JvmName
 
 
 /**
- * Simplified [DoubleBuffer] to array comparison
+ * Simplified [Float64Buffer] to array comparison
  */
 public fun OffsetDoubleBuffer.contentEquals(vararg doubles: Double): Boolean = indices.all { get(it) == doubles[it] }
 
diff --git a/kmath-tensors/src/jvmTest/kotlin/space/kscience/kmath/tensors/core/TestLmAlgorithm.kt b/kmath-tensors/src/jvmTest/kotlin/space/kscience/kmath/tensors/core/TestLmAlgorithm.kt
new file mode 100644
index 000000000..6c072d52b
--- /dev/null
+++ b/kmath-tensors/src/jvmTest/kotlin/space/kscience/kmath/tensors/core/TestLmAlgorithm.kt
@@ -0,0 +1,310 @@
+/*
+ * Copyright 2018-2024 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.tensors.core
+
+import space.kscience.kmath.PerformancePitfall
+import space.kscience.kmath.nd.*
+import space.kscience.kmath.operations.invoke
+import space.kscience.kmath.structures.Float64Buffer
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+@PerformancePitfall
+class TestLmAlgorithm {
+    companion object {
+        fun funcEasyForLm(
+            t: MutableStructure2D<Double>,
+            p: MutableStructure2D<Double>,
+            exampleNumber: Int,
+        ): MutableStructure2D<Double> = with(DoubleTensorAlgebra) {
+            val m = t.shape.component1()
+            val yHat = when (exampleNumber) {
+                1 -> exp((t * (-1.0 / p[1, 0]))) * p[0, 0] + (t * p[2, 0]) * exp((t * (-1.0 / p[3, 0])))
+
+                2 -> {
+                    val mt = t.max()
+                    (t * (1.0 / mt)) * p[0, 0] +
+                            (t * (1.0 / mt)).pow(2) * p[1, 0] +
+                            (t * (1.0 / mt)).pow(3) * p[2, 0] +
+                            (t * (1.0 / mt)).pow(4) * p[3, 0]
+                }
+
+                3 -> exp(t * (-1.0 / p[1, 0])) * p[0, 0] +
+                        sin((t * (1.0 / p[3, 0]))) * p[2, 0]
+
+                else -> zeros(ShapeND(intArrayOf(m, 1)))
+            }
+
+            return yHat.as2D()
+        }
+
+        fun funcMiddleForLm(
+            t: MutableStructure2D<Double>,
+            p: MutableStructure2D<Double>,
+            exampleNumber: Int,
+        ): MutableStructure2D<Double> = with(DoubleTensorAlgebra) {
+            val m = t.shape.component1()
+            var yHat = zeros(ShapeND(intArrayOf(m, 1)))
+
+            val mt = t.max()
+            for (i in 0 until p.shape.component1()) {
+                yHat.plusAssign(t * (1.0 / mt) * p[i, 0])
+            }
+
+            for (i in 0 until 5) {
+                yHat = funcEasyForLm(yHat.as2D(), p, exampleNumber).asDoubleTensor()
+            }
+
+            return yHat.as2D()
+        }
+
+        fun funcDifficultForLm(
+            t: MutableStructure2D<Double>,
+            p: MutableStructure2D<Double>,
+            exampleNumber: Int,
+        ): MutableStructure2D<Double> = with(DoubleTensorAlgebra) {
+            val m = t.shape.component1()
+            var yHat = zeros(ShapeND(intArrayOf(m, 1)))
+
+            val mt = t.max()
+            for (i in 0 until p.shape.component1()) {
+                yHat = yHat + (t * (1.0 / mt)) * p[i, 0]
+            }
+
+            for (i in 0 until 4) {
+                yHat = funcEasyForLm((yHat.as2D() + t).as2D(), p, exampleNumber).asDoubleTensor()
+            }
+
+            return yHat.as2D()
+        }
+    }
+
+    @Test
+    fun testLMEasy() = DoubleTensorAlgebra {
+        val lmMatxYDat = doubleArrayOf(
+            19.6594, 18.6096, 17.6792, 17.2747, 16.3065, 17.1458, 16.0467, 16.7023, 15.7809, 15.9807,
+            14.7620, 15.1128, 16.0973, 15.1934, 15.8636, 15.4763, 15.6860, 15.1895, 15.3495, 16.6054,
+            16.2247, 15.9854, 16.1421, 17.0960, 16.7769, 17.1997, 17.2767, 17.5882, 17.5378, 16.7894,
+            17.7648, 18.2512, 18.1581, 16.7037, 17.8475, 17.9081, 18.3067, 17.9632, 18.2817, 19.1427,
+            18.8130, 18.5658, 18.0056, 18.4607, 18.5918, 18.2544, 18.3731, 18.7511, 19.3181, 17.3066,
+            17.9632, 19.0513, 18.7528, 18.2928, 18.5967, 17.8567, 17.7859, 18.4016, 18.9423, 18.4959,
+            17.8000, 18.4251, 17.7829, 17.4645, 17.5221, 17.3517, 17.4637, 17.7563, 16.8471, 17.4558,
+            17.7447, 17.1487, 17.3183, 16.8312, 17.7551, 17.0942, 15.6093, 16.4163, 15.3755, 16.6725,
+            16.2332, 16.2316, 16.2236, 16.5361, 15.3721, 15.3347, 15.5815, 15.6319, 14.4538, 14.6044,
+            14.7665, 13.3718, 15.0587, 13.8320, 14.7873, 13.6824, 14.2579, 14.2154, 13.5818, 13.8157
+        )
+
+        val exampleNumber = 1
+        val pInit = fromArray(
+            ShapeND(intArrayOf(4, 1)), doubleArrayOf(5.0, 2.0, 0.2, 10.0)
+        ).as2D()
+
+        val t = ones(ShapeND(intArrayOf(100, 1))).as2D()
+        for (i in 0 until 100) {
+            t[i, 0] = t[i, 0] * (i + 1)
+        }
+
+        val yDat = BroadcastDoubleTensorAlgebra.fromArray(
+            ShapeND(intArrayOf(100, 1)), lmMatxYDat
+        ).as2D()
+
+        val weight = 4.0
+
+        val dp = BroadcastDoubleTensorAlgebra.fromArray(
+            ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }
+        ).as2D()
+
+        val pMin = BroadcastDoubleTensorAlgebra.fromArray(
+            ShapeND(intArrayOf(4, 1)), doubleArrayOf(-50.0, -20.0, -2.0, -100.0)
+        ).as2D()
+
+        val pMax = BroadcastDoubleTensorAlgebra.fromArray(
+            ShapeND(intArrayOf(4, 1)), doubleArrayOf(50.0, 20.0, 2.0, 100.0)
+        ).as2D()
+
+        val inputData = LMInput(
+            Companion::funcEasyForLm, pInit, t, yDat, weight, dp, pMin, pMax, 100,
+            doubleArrayOf(1e-3, 1e-3, 1e-1, 1e-1), doubleArrayOf(1e-2, 11.0, 9.0), 1, 10, exampleNumber
+        )
+
+        val result = levenbergMarquardt(inputData)
+        assertEquals(13, result.iterations)
+        assertEquals(31, result.funcCalls)
+        assertEquals(0.9131368192633, result.resultChiSq, 1e-13)
+        assertEquals(3.7790980 * 1e-7, result.resultLambda, 1e-13)
+        assertEquals(result.typeOfConvergence, TypeOfConvergence.InParameters)
+        val expectedParameters = BroadcastDoubleTensorAlgebra.fromArray(
+            ShapeND(intArrayOf(4, 1)), doubleArrayOf(20.527230909086, 9.833627103230, 0.997571256572, 50.174445822506)
+        ).as2D()
+        result.resultParameters = result.resultParameters.map { x -> (x * 1e12).toLong() / 1e12 }.as2D()
+        val receivedParameters = BroadcastDoubleTensorAlgebra.fromArray(
+            ShapeND(intArrayOf(4, 1)), doubleArrayOf(
+                result.resultParameters[0, 0], result.resultParameters[1, 0],
+                result.resultParameters[2, 0], result.resultParameters[3, 0]
+            )
+        ).as2D()
+        assertEquals(expectedParameters[0, 0], receivedParameters[0, 0])
+        assertEquals(expectedParameters[1, 0], receivedParameters[1, 0])
+        assertEquals(expectedParameters[2, 0], receivedParameters[2, 0])
+        assertEquals(expectedParameters[3, 0], receivedParameters[3, 0])
+    }
+
+    @Test
+    fun testLMMiddle() = DoubleTensorAlgebra {
+        val nData = 100
+        val tExample = one(nData, 1).as2D()
+        for (i in 0 until nData) {
+            tExample[i, 0] = tExample[i, 0] * (i + 1)
+        }
+
+        val nParams = 20
+        val pExample = one(nParams, 1).as2D()
+        for (i in 0 until nParams) {
+            pExample[i, 0] = pExample[i, 0] + i - 25
+        }
+
+        val exampleNumber = 1
+
+        val yHat = funcMiddleForLm(tExample, pExample, exampleNumber)
+
+        val pInit = zeros(ShapeND(intArrayOf(nParams, 1))).as2D()
+        for (i in 0 until nParams) {
+            pInit[i, 0] = (pExample[i, 0] + 0.9)
+        }
+
+        val t = tExample
+        val yDat = yHat
+        val weight = 1.0
+        val dp = BroadcastDoubleTensorAlgebra.fromArray(
+            ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }
+        ).as2D()
+        var pMin = ones(ShapeND(intArrayOf(nParams, 1)))
+        pMin = pMin * (-50.0)
+        val pMax = ones(ShapeND(intArrayOf(nParams, 1)))
+        pMin = pMin * 50.0
+        val opts = doubleArrayOf(3.0, 7000.0, 1e-5, 1e-5, 1e-5, 1e-5, 1e-5, 11.0, 9.0, 1.0)
+
+        val inputData = LMInput(
+            Companion::funcMiddleForLm,
+            pInit.as2D(),
+            t,
+            yDat,
+            weight,
+            dp,
+            pMin.as2D(),
+            pMax.as2D(),
+            opts[1].toInt(),
+            doubleArrayOf(opts[2], opts[3], opts[4], opts[5]),
+            doubleArrayOf(opts[6], opts[7], opts[8]),
+            opts[9].toInt(),
+            10,
+            1
+        )
+
+        val result = DoubleTensorAlgebra.levenbergMarquardt(inputData)
+
+        assertEquals(46, result.iterations)
+        assertEquals(113, result.funcCalls)
+        assertEquals(0.000005977, result.resultChiSq, 1e-9)
+        assertEquals(1.0 * 1e-7, result.resultLambda, 1e-13)
+        assertEquals(result.typeOfConvergence, TypeOfConvergence.InReducedChiSquare)
+        val expectedParameters = fromArray(
+            ShapeND(intArrayOf(nParams, 1)), doubleArrayOf(
+                -23.9717, -18.6686, -21.7971,
+                -20.9681, -22.086, -20.5859, -19.0384, -17.4957, -15.9991, -14.576, -13.2441, -
+                12.0201, -10.9256, -9.9878, -9.2309, -8.6589, -8.2365, -7.8783, -7.4598, -6.8511
+            )
+        )
+        val receivedParameters = zero(nParams, 1)
+        for (i in 0 until nParams) {
+            receivedParameters[i, 0] = result.resultParameters[i, 0]
+            assertEquals(expectedParameters[i, 0], result.resultParameters[i, 0], 1e-2)
+        }
+    }
+
+    @Test
+    fun TestLMDifficult() = DoubleTensorAlgebra {
+        val nData = 200
+        val tExample = ones(ShapeND(intArrayOf(nData, 1))).as2D()
+        for (i in 0 until nData) {
+            tExample[i, 0] = tExample[i, 0] * (i + 1) - 104
+        }
+
+        val nParams = 15
+        val pExample = ones(ShapeND(intArrayOf(nParams, 1))).as2D()
+        for (i in 0 until nParams) {
+            pExample[i, 0] = pExample[i, 0] + i - 25
+        }
+
+        val exampleNumber = 1
+
+        val yHat = funcDifficultForLm(tExample, pExample, exampleNumber)
+
+        val pInit = zeros(ShapeND(intArrayOf(nParams, 1))).as2D()
+        for (i in 0 until nParams) {
+            pInit[i, 0] = (pExample[i, 0] + 0.9)
+        }
+
+        val t = tExample
+        val yDat = yHat
+        val weight = 1.0 / nParams * 1.0 - 0.085
+        val dp = fromArray(
+            ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }
+        ).as2D()
+        var pMin = ones(ShapeND(intArrayOf(nParams, 1)))
+        pMin = pMin * (-50.0)
+        val pMax = ones(ShapeND(intArrayOf(nParams, 1)))
+        pMin = pMin * (50.0)
+        val opts = doubleArrayOf(3.0, 7000.0, 1e-2, 1e-3, 1e-2, 1e-2, 1e-2, 11.0, 9.0, 1.0)
+
+        val inputData = LMInput(
+            Companion::funcDifficultForLm,
+            pInit.as2D(),
+            t,
+            yDat,
+            weight,
+            dp,
+            pMin.as2D(),
+            pMax.as2D(),
+            opts[1].toInt(),
+            doubleArrayOf(opts[2], opts[3], opts[4], opts[5]),
+            doubleArrayOf(opts[6], opts[7], opts[8]),
+            opts[9].toInt(),
+            10,
+            1
+        )
+
+        val result = DoubleTensorAlgebra.levenbergMarquardt(inputData)
+
+        assertEquals(2375, result.iterations)
+        assertEquals(4858, result.funcCalls)
+        assertEquals(5.14347, result.resultLambda, 1e-5)
+        assertEquals(result.typeOfConvergence, TypeOfConvergence.InParameters)
+        val expectedParameters = Float64Buffer(
+            -23.6412,
+            -16.7402,
+            -21.5705,
+            -21.0464,
+            -17.2852,
+            -17.2959,
+            -17.298,
+            0.9999,
+            -17.2885,
+            -17.3008,
+            -17.2941,
+            -17.2923,
+            -17.2976,
+            -17.3028,
+            -17.2891
+        )
+
+        val receivedParameters = zeros(ShapeND(intArrayOf(nParams, 1))).as2D()
+        for (i in 0 until nParams) {
+            receivedParameters[i, 0] = result.resultParameters[i, 0]
+            assertEquals(expectedParameters[i], result.resultParameters[i, 0], 1e-2)
+        }
+    }
+}
\ No newline at end of file
diff --git a/kmath-viktor/README.md b/kmath-viktor/README.md
index 8a781af4c..73c8c8774 100644
--- a/kmath-viktor/README.md
+++ b/kmath-viktor/README.md
@@ -6,19 +6,8 @@ Binding for https://github.com/JetBrains-Research/viktor
 
 ## Artifact:
 
-The Maven coordinates of this project are `space.kscience:kmath-viktor:0.4.0-dev-1`.
+The Maven coordinates of this project are `space.kscience:kmath-viktor:0.4.0`.
 
-**Gradle Groovy:**
-```groovy
-repositories {
-    maven { url 'https://repo.kotlin.link' }
-    mavenCentral()
-}
-
-dependencies {
-    implementation 'space.kscience:kmath-viktor:0.4.0-dev-1'
-}
-```
 **Gradle Kotlin DSL:**
 ```kotlin
 repositories {
@@ -27,6 +16,6 @@ repositories {
 }
 
 dependencies {
-    implementation("space.kscience:kmath-viktor:0.4.0-dev-1")
+    implementation("space.kscience:kmath-viktor:0.4.0")
 }
 ```
diff --git a/kmath-viktor/api/kmath-viktor.api b/kmath-viktor/api/kmath-viktor.api
index 39ae1f84c..0ad7368a9 100644
--- a/kmath-viktor/api/kmath-viktor.api
+++ b/kmath-viktor/api/kmath-viktor.api
@@ -1,8 +1,6 @@
 public final class space/kscience/kmath/viktor/ViktorBuffer : space/kscience/kmath/structures/MutableBuffer {
 	public static final synthetic fun box-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;)Lspace/kscience/kmath/viktor/ViktorBuffer;
 	public static fun constructor-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;)Lorg/jetbrains/bio/viktor/F64FlatArray;
-	public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer;
-	public static fun copy-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;)Lspace/kscience/kmath/structures/MutableBuffer;
 	public fun equals (Ljava/lang/Object;)Z
 	public static fun equals-impl (Lorg/jetbrains/bio/viktor/F64FlatArray;Ljava/lang/Object;)Z
 	public static final fun equals-impl0 (Lorg/jetbrains/bio/viktor/F64FlatArray;Lorg/jetbrains/bio/viktor/F64FlatArray;)Z
@@ -62,7 +60,7 @@ public class space/kscience/kmath/viktor/ViktorFieldOpsND : space/kscience/kmath
 	public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object;
 	public fun exp (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND;
 	public synthetic fun getElementAlgebra ()Lspace/kscience/kmath/operations/Algebra;
-	public fun getElementAlgebra ()Lspace/kscience/kmath/operations/DoubleField;
+	public fun getElementAlgebra ()Lspace/kscience/kmath/operations/Float64Field;
 	public final fun getF64Buffer (Lspace/kscience/kmath/nd/StructureND;)Lorg/jetbrains/bio/viktor/F64Array;
 	public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object;
 	public fun ln (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND;
@@ -72,6 +70,8 @@ public class space/kscience/kmath/viktor/ViktorFieldOpsND : space/kscience/kmath
 	public fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/viktor/ViktorStructureND;
 	public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
 	public fun minus (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND;
+	public synthetic fun mutableStructureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/MutableStructureND;
+	public fun mutableStructureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/viktor/ViktorStructureND;
 	public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
 	public fun plus (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/viktor/ViktorStructureND;
 	public synthetic fun plus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND;
@@ -85,8 +85,6 @@ public class space/kscience/kmath/viktor/ViktorFieldOpsND : space/kscience/kmath
 	public fun sin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND;
 	public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object;
 	public fun sinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND;
-	public synthetic fun structureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND;
-	public fun structureND-qL90JFI ([ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/viktor/ViktorStructureND;
 	public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object;
 	public fun tan (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND;
 	public synthetic fun times (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
@@ -102,8 +100,8 @@ public final class space/kscience/kmath/viktor/ViktorFieldOpsND$Companion : spac
 
 public final class space/kscience/kmath/viktor/ViktorFieldOpsNDKt {
 	public static final fun ViktorFieldND ([I)Lspace/kscience/kmath/viktor/ViktorFieldND;
-	public static final fun getViktorAlgebra (Lspace/kscience/kmath/operations/DoubleField;)Lspace/kscience/kmath/viktor/ViktorFieldOpsND;
-	public static final fun viktorAlgebra (Lspace/kscience/kmath/operations/DoubleField;[I)Lspace/kscience/kmath/viktor/ViktorFieldND;
+	public static final fun getViktorAlgebra (Lspace/kscience/kmath/operations/Float64Field;)Lspace/kscience/kmath/viktor/ViktorFieldOpsND;
+	public static final fun viktorAlgebra (Lspace/kscience/kmath/operations/Float64Field;[I)Lspace/kscience/kmath/viktor/ViktorFieldND;
 }
 
 public final class space/kscience/kmath/viktor/ViktorStructureND : space/kscience/kmath/nd/MutableStructureND {
diff --git a/kmath-viktor/build.gradle.kts b/kmath-viktor/build.gradle.kts
index 7a135f316..d15a70e9b 100644
--- a/kmath-viktor/build.gradle.kts
+++ b/kmath-viktor/build.gradle.kts
@@ -10,5 +10,5 @@ dependencies {
 }
 
 readme {
-    maturity = space.kscience.gradle.Maturity.DEVELOPMENT
+    maturity = space.kscience.gradle.Maturity.DEPRECATED
 }
diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt
index 52dc1e192..89b51f269 100644
--- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt
+++ b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -12,6 +12,7 @@ import space.kscience.kmath.structures.MutableBuffer
 @Suppress("NOTHING_TO_INLINE", "OVERRIDE_BY_INLINE")
 @JvmInline
 public value class ViktorBuffer(public val flatArray: F64FlatArray) : MutableBuffer<Double> {
+
     override val size: Int
         get() = flatArray.length
 
@@ -21,7 +22,6 @@ public value class ViktorBuffer(public val flatArray: F64FlatArray) : MutableBuf
         flatArray[index] = value
     }
 
-    override fun copy(): MutableBuffer<Double> = ViktorBuffer(flatArray.copy().flatten())
     override operator fun iterator(): Iterator<Double> = flatArray.data.iterator()
 
     override fun toString(): String = Buffer.toString(this)
diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt
index 8c7d6d199..1d95546ac 100644
--- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt
+++ b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
@@ -12,31 +12,30 @@ import space.kscience.kmath.PerformancePitfall
 import space.kscience.kmath.UnsafeKMathAPI
 import space.kscience.kmath.UnstableKMathAPI
 import space.kscience.kmath.nd.*
-import space.kscience.kmath.operations.DoubleField
 import space.kscience.kmath.operations.ExtendedFieldOps
+import space.kscience.kmath.operations.Float64Field
 import space.kscience.kmath.operations.NumbersAddOps
 import space.kscience.kmath.operations.PowerOperations
 
-@OptIn(UnstableKMathAPI::class, PerformancePitfall::class)
-@Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
+@OptIn(PerformancePitfall::class)
 public open class ViktorFieldOpsND :
-    FieldOpsND<Double, DoubleField>,
+    FieldOpsND<Double, Float64Field>,
     ExtendedFieldOps<StructureND<Double>>,
     PowerOperations<StructureND<Double>> {
 
     public val StructureND<Double>.f64Buffer: F64Array
         get() = when (this) {
             is ViktorStructureND -> this.f64Buffer
-            else -> structureND(shape) { this@f64Buffer[it] }.f64Buffer
+            else -> mutableStructureND(shape) { this@f64Buffer[it] }.f64Buffer
         }
 
-    override val elementAlgebra: DoubleField get() = DoubleField
+    override val elementAlgebra: Float64Field get() = Float64Field
 
     @OptIn(UnsafeKMathAPI::class)
-    override fun structureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): ViktorStructureND =
+    override fun mutableStructureND(shape: ShapeND, initializer: Float64Field.(IntArray) -> Double): ViktorStructureND =
         F64Array(*shape.asArray()).apply {
             ColumnStrides(shape).asSequence().forEach { index ->
-                set(value = DoubleField.initializer(index), indices = index)
+                set(value = Float64Field.initializer(index), indices = index)
             }
         }.asStructure()
 
@@ -44,20 +43,20 @@ public open class ViktorFieldOpsND :
 
     @OptIn(UnsafeKMathAPI::class)
     @PerformancePitfall
-    override fun StructureND<Double>.map(transform: DoubleField.(Double) -> Double): ViktorStructureND =
+    override fun StructureND<Double>.map(transform: Float64Field.(Double) -> Double): ViktorStructureND =
         F64Array(*shape.asArray()).apply {
             ColumnStrides(ShapeND(shape)).asSequence().forEach { index ->
-                set(value = DoubleField.transform(this@map[index]), indices = index)
+                set(value = Float64Field.transform(this@map[index]), indices = index)
             }
         }.asStructure()
 
     @OptIn(UnsafeKMathAPI::class)
     @PerformancePitfall
     override fun StructureND<Double>.mapIndexed(
-        transform: DoubleField.(index: IntArray, Double) -> Double,
+        transform: Float64Field.(index: IntArray, Double) -> Double,
     ): ViktorStructureND = F64Array(*shape.asArray()).apply {
         ColumnStrides(ShapeND(shape)).asSequence().forEach { index ->
-            set(value = DoubleField.transform(index, this@mapIndexed[index]), indices = index)
+            set(value = Float64Field.transform(index, this@mapIndexed[index]), indices = index)
         }
     }.asStructure()
 
@@ -66,12 +65,12 @@ public open class ViktorFieldOpsND :
     override fun zip(
         left: StructureND<Double>,
         right: StructureND<Double>,
-        transform: DoubleField.(Double, Double) -> Double,
+        transform: Float64Field.(Double, Double) -> Double,
     ): ViktorStructureND {
         require(left.shape.contentEquals(right.shape))
         return F64Array(*left.shape.asArray()).apply {
             ColumnStrides(left.shape).asSequence().forEach { index ->
-                set(value = DoubleField.transform(left[index], right[index]), indices = index)
+                set(value = Float64Field.transform(left[index], right[index]), indices = index)
             }
         }.asStructure()
     }
@@ -120,12 +119,12 @@ public open class ViktorFieldOpsND :
     public companion object : ViktorFieldOpsND()
 }
 
-public val DoubleField.viktorAlgebra: ViktorFieldOpsND get() = ViktorFieldOpsND
+public val Float64Field.viktorAlgebra: ViktorFieldOpsND get() = ViktorFieldOpsND
 
 @OptIn(UnstableKMathAPI::class)
 public open class ViktorFieldND(
     private val shapeAsArray: IntArray,
-) : ViktorFieldOpsND(), FieldND<Double, DoubleField>, NumbersAddOps<StructureND<Double>> {
+) : ViktorFieldOpsND(), FieldND<Double, Float64Field>, NumbersAddOps<StructureND<Double>> {
 
     override val shape: ShapeND = ShapeND(shapeAsArray)
 
@@ -137,6 +136,6 @@ public open class ViktorFieldND(
         F64Array.full(init = value.toDouble(), shape = shapeAsArray).asStructure()
 }
 
-public fun DoubleField.viktorAlgebra(vararg shape: Int): ViktorFieldND = ViktorFieldND(shape)
+public fun Float64Field.viktorAlgebra(vararg shape: Int): ViktorFieldND = ViktorFieldND(shape)
 
 public fun ViktorFieldND(vararg shape: Int): ViktorFieldND = ViktorFieldND(shape)
\ No newline at end of file
diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt
index 7c0c02086..328a0ab01 100644
--- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt
+++ b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/settings.gradle.kts b/settings.gradle.kts
index f158f3444..e660bef85 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -21,6 +21,7 @@ dependencyResolutionManagement {
 
 include(
     ":test-utils",
+    ":attributes-kt",
     ":kmath-memory",
     ":kmath-complex",
     ":kmath-core",
diff --git a/test-utils/api/test-utils.api b/test-utils/api/test-utils.api
index fc812a9a6..2915fa039 100644
--- a/test-utils/api/test-utils.api
+++ b/test-utils/api/test-utils.api
@@ -4,7 +4,7 @@ public final class space/kscience/kmath/testutils/AssertsKt {
 }
 
 public final class space/kscience/kmath/testutils/BufferEqualityKt {
-	public static final fun contentEquals-2c9zdjM ([D[D)Z
+	public static final fun contentEquals-YsAwp1c ([D[D)Z
 	public static final fun contentEqualsArray ([D[D)Z
 	public static final fun contentEqualsBuffer ([D[D)Z
 }
diff --git a/test-utils/build.gradle.kts b/test-utils/build.gradle.kts
index b03059eaf..663b1149b 100644
--- a/test-utils/build.gradle.kts
+++ b/test-utils/build.gradle.kts
@@ -2,7 +2,7 @@ plugins {
     id("space.kscience.gradle.mpp")
 }
 
-kscience{
+kscience {
     jvm()
     js()
     native()
diff --git a/test-utils/src/commonMain/kotlin/AlgebraicVerifier.kt b/test-utils/src/commonMain/kotlin/AlgebraicVerifier.kt
index 261e74f5a..33e7b5972 100644
--- a/test-utils/src/commonMain/kotlin/AlgebraicVerifier.kt
+++ b/test-utils/src/commonMain/kotlin/AlgebraicVerifier.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/test-utils/src/commonMain/kotlin/FieldVerifier.kt b/test-utils/src/commonMain/kotlin/FieldVerifier.kt
index a03ca0a27..3b3acd32c 100644
--- a/test-utils/src/commonMain/kotlin/FieldVerifier.kt
+++ b/test-utils/src/commonMain/kotlin/FieldVerifier.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/test-utils/src/commonMain/kotlin/RingVerifier.kt b/test-utils/src/commonMain/kotlin/RingVerifier.kt
index c40075d93..0a1237b60 100644
--- a/test-utils/src/commonMain/kotlin/RingVerifier.kt
+++ b/test-utils/src/commonMain/kotlin/RingVerifier.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/test-utils/src/commonMain/kotlin/SpaceVerifier.kt b/test-utils/src/commonMain/kotlin/SpaceVerifier.kt
index 01c02997b..ae805db5a 100644
--- a/test-utils/src/commonMain/kotlin/SpaceVerifier.kt
+++ b/test-utils/src/commonMain/kotlin/SpaceVerifier.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/test-utils/src/commonMain/kotlin/asserts.kt b/test-utils/src/commonMain/kotlin/asserts.kt
index 8ddce517c..54c6301b6 100644
--- a/test-utils/src/commonMain/kotlin/asserts.kt
+++ b/test-utils/src/commonMain/kotlin/asserts.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
diff --git a/test-utils/src/commonMain/kotlin/bufferEquality.kt b/test-utils/src/commonMain/kotlin/bufferEquality.kt
index 9e4d9ec22..d4fd99506 100644
--- a/test-utils/src/commonMain/kotlin/bufferEquality.kt
+++ b/test-utils/src/commonMain/kotlin/bufferEquality.kt
@@ -1,20 +1,21 @@
 /*
- * Copyright 2018-2022 KMath contributors.
+ * Copyright 2018-2024 KMath contributors.
  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
  */
 
 package space.kscience.kmath.testutils
 
-import space.kscience.kmath.structures.DoubleBuffer
+import space.kscience.kmath.structures.Float64Buffer
 import kotlin.jvm.JvmName
 
 /**
- * Simplified [DoubleBuffer] to array comparison
+ * Simplified [Float64Buffer] to array comparison
  */
-public fun DoubleBuffer.contentEquals(vararg doubles: Double): Boolean = array.contentEquals(doubles)
+public fun Float64Buffer.contentEquals(vararg doubles: Double): Boolean = array.contentEquals(doubles)
 
 @JvmName("contentEqualsArray")
-public infix fun DoubleBuffer.contentEquals(otherArray: DoubleArray): Boolean = array.contentEquals(otherArray)
+public infix fun Float64Buffer.contentEquals(otherArray: DoubleArray): Boolean = array.contentEquals(otherArray)
 
 @JvmName("contentEqualsBuffer")
-public infix fun DoubleBuffer.contentEquals(otherBuffer: DoubleBuffer): Boolean = array.contentEquals(otherBuffer.array)
\ No newline at end of file
+public infix fun Float64Buffer.contentEquals(otherBuffer: Float64Buffer): Boolean =
+    array.contentEquals(otherBuffer.array)
\ No newline at end of file