
Multidimensional array library offering ndarray creation, mathematical operations, linear algebra, and statistical functions. Supports various backends for performance, including native code via OpenBLAS. Integrates with Jupyter Notebooks.
Multidimensional array library for Kotlin.
Multik provides N-dimensional arrays with type-safe dimensions, math operations, linear algebra, and statistics. It works across JVM, JS, WasmJS, iOS, and desktop native targets via Kotlin Multiplatform, with optional OpenBLAS acceleration for high performance.
| Module | Description |
|---|---|
| multik-core | Core ndarray types, the mk entry point, and Math/LinAlg/Statistics API interfaces. All platforms. |
| multik-default | Combines multik-kotlin and multik-openblas for optimal performance on every platform. |
| multik-kotlin | Pure Kotlin implementation. JVM, JS, WasmJS, iOS, and desktop native. |
| multik-openblas | Native implementation backed by OpenBLAS via C++/JNI. JVM and desktop native (macOS, Linux, Windows). |
multik-core provides ndarray types, creation functions, and basic operations.
For linear algebra, statistics, and math engines, add an engine dependency —
multik-default, multik-kotlin, or multik-openblas.
Engine dependencies transitively include multik-core.
build.gradle.kts:
repositories {
mavenCentral()
}
dependencies {
implementation("org.jetbrains.kotlinx:multik-default:$multikVersion")
}build.gradle:
repositories {
mavenCentral()
}
dependencies {
implementation "org.jetbrains.kotlinx:multik-default:$multikVersion"
}kotlin {
sourceSets {
commonMain {
dependencies {
implementation("org.jetbrains.kotlinx:multik-default:$multikVersion")
}
}
}
}Install Kotlin kernel for Jupyter or just visit to Datalore.
Import stable multik version into notebook:
%use multik
| Platform | multik-core |
multik-kotlin |
multik-openblas |
multik-default |
|---|---|---|---|---|
| JVM | ✅ | ✅ | ✅ | ✅ |
| JS | ✅ | ✅ | — | ✅ |
| WasmJS | ✅ | ✅ | — | ✅ |
| linuxX64 | ✅ | ✅ | ✅ | ✅ |
| mingwX64 | ✅ | ✅ | ✅ | ✅ |
| macosX64 | ✅ | ✅ | ✅ | ✅ |
| macosArm64 | ✅ | ✅ | ✅ | ✅ |
| iosArm64 | ✅ | ✅ | — | ✅ |
| iosX64 | ✅ | ✅ | — | ✅ |
| iosSimulatorArm64 | ✅ | ✅ | — | ✅ |
[!IMPORTANT]
- On Ubuntu 18.04 and older,
multik-openblasdoesn't work due to older versions of glibc.multik-openblasfor desktop native targets (linuxX64, mingwX64, macosX64, macosArm64) is experimental and unstable.- JVM target
multik-openblasfor Android only supports arm64-v8a processors.
Visit Multik documentation for a detailed feature overview.
val a = mk.ndarray(mk[1, 2, 3])
/* [1, 2, 3] */
val b = mk.ndarray(mk[mk[1.5, 2.1, 3.0], mk[4.0, 5.0, 6.0]])
/*
[[1.5, 2.1, 3.0],
[4.0, 5.0, 6.0]]
*/
val c = mk.ndarray(mk[mk[mk[1.5f, 2f, 3f], mk[4f, 5f, 6f]], mk[mk[3f, 2f, 1f], mk[4f, 5f, 6f]]])
/*
[[[1.5, 2.0, 3.0],
[4.0, 5.0, 6.0]],
[[3.0, 2.0, 1.0],
[4.0, 5.0, 6.0]]]
*/
mk.zeros<Double>(3, 4) // create an array of zeros
/*
[[0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0]]
*/
mk.ndarray<Float, D2>(setOf(30f, 2f, 13f, 12f), intArrayOf(2, 2)) // create an array from a collection
/*
[[30.0, 2.0],
[13.0, 12.0]]
*/
val d = mk.ndarray(
doubleArrayOf(1.0, 1.3, 3.0, 4.0, 9.5, 5.0),
2,
3
) // create an array of shape(2, 3) from a primitive array
/*
[[1.0, 1.3, 3.0],
[4.0, 9.5, 5.0]]
*/
mk.d3array(2, 2, 3) { it * it } // create an array of 3 dimension
/*
[[[0, 1, 4],
[9, 16, 25]],
[[36, 49, 64],
[81, 100, 121]]]
*/
mk.d2arrayIndices(3, 3) { i, j -> ComplexFloat(i, j) }
/*
[[0.0+(0.0)i, 0.0+(1.0)i, 0.0+(2.0)i],
[1.0+(0.0)i, 1.0+(1.0)i, 1.0+(2.0)i],
[2.0+(0.0)i, 2.0+(1.0)i, 2.0+(2.0)i]]
*/
mk.arange<Long>(10, 25, 5) // create an array with elements in the interval [10, 25) with step 5
/* [10, 15, 20] */
mk.linspace<Double>(0, 2, 9) // create an array of 9 elements in the interval [0, 2]
/* [0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0] */
val e = mk.identity<Double>(3) // create an identity array of shape (3, 3)
/*
[[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0]]
*/
val diag = mk.diagonal(mk[2, 4, 8]) // create a diagonal array
/*
[[2, 0, 0],
[0, 4, 0],
[0, 0, 8]]
*/a.shape // Array dimensions
a.size // Size of array
a.dim // object Dimension
a.dim.d // number of array dimensions
a.dtype // Data type of array elementsval f = b - d // subtraction
/*
[[0.5, 0.8, 0.0],
[0.0, -4.5, 1.0]]
*/
d + f // addition
/*
[[1.5, 2.1, 3.0],
[4.0, 5.0, 6.0]]
*/
b / d // division
/*
[[1.5, 1.6153846153846154, 1.0],
[1.0, 0.5263157894736842, 1.2]]
*/
f * d // multiplication
/*
[[0.5, 1.04, 0.0],
[0.0, -42.75, 5.0]]
*/See documentation for other methods of mathematics, linear algebra, statistics.
a.sin() // element-wise sin, equivalent to mk.math.sin(a)
a.cos() // element-wise cos, equivalent to mk.math.cos(a)
b.log() // element-wise natural logarithm, equivalent to mk.math.log(b)
b.exp() // element-wise exp, equivalent to mk.math.exp(b)
d dot e // dot product, equivalent to mk.linalg.dot(d, e)
mk.math.sum(c) // array-wise sum
mk.math.min(c) // array-wise minimum elements
mk.math.maxD3(c, axis = 0) // maximum value of an array along axis 0
mk.math.cumSum(b, axis = 1) // cumulative sum of the elements
mk.stat.mean(a) // mean
mk.stat.median(b) // medianval f = a.copy() // create a copy of the array and its data
val h = b.deepCopy() // create a copy of the array and copy the meaningful datac.filter { it < 3 } // select all elements less than 3
b.map { (it * it).toInt() } // return squares
c.groupNDArrayBy { it % 2 } // group elements by condition
c.sorted() // sort elementsa[2] // select the element at the 2 index
b[1, 2] // select the element at row 1 column 2
b[1] // select row 1
b[0..1, 1] // select elements at rows 0 to 1 in column 1
b[0, 0..2..1] // select elements at row 0 in columns 0 to 2 with step 1
for (el in b) {
print("$el, ") // 1.5, 2.1, 3.0, 4.0, 5.0, 6.0,
}
// for n-dimensional
val q = b.asDNArray()
for (index in q.multiIndices) {
print("${q[index]}, ") // 1.5, 2.1, 3.0, 4.0, 5.0, 6.0,
}val a = mk.linspace<Float>(0, 1, 10)
/*
a = [0.0, 0.1111111111111111, 0.2222222222222222, 0.3333333333333333, 0.4444444444444444, 0.5555555555555556,
0.6666666666666666, 0.7777777777777777, 0.8888888888888888, 1.0]
*/
val b = mk.linspace<Float>(8, 9, 10)
/*
b = [8.0, 8.11111111111111, 8.222222222222221, 8.333333333333334, 8.444444444444445, 8.555555555555555,
8.666666666666666, 8.777777777777779, 8.88888888888889, 9.0]
*/
a.inplace {
math {
(this - b) * b
abs()
}
}
// a = [64.0, 64.88888, 65.77778, 66.66666, 67.55556, 68.44444, 69.333336, 70.22222, 71.111115, 72.0]Requires:
JAVA_HOME environment variable setgcc, g++, gfortran version 8 or higher (must be the same version)./gradlew assemble./gradlew assemble -x build_cmake./gradlew :multik-core:build./gradlew :multik-core:jvmTestSee CONTRIBUTING.md for guidelines on submitting issues, pull requests, and building the project.
Multik is licensed under the Apache License 2.0.
Multidimensional array library for Kotlin.
Multik provides N-dimensional arrays with type-safe dimensions, math operations, linear algebra, and statistics. It works across JVM, JS, WasmJS, iOS, and desktop native targets via Kotlin Multiplatform, with optional OpenBLAS acceleration for high performance.
| Module | Description |
|---|---|
| multik-core | Core ndarray types, the mk entry point, and Math/LinAlg/Statistics API interfaces. All platforms. |
| multik-default | Combines multik-kotlin and multik-openblas for optimal performance on every platform. |
| multik-kotlin | Pure Kotlin implementation. JVM, JS, WasmJS, iOS, and desktop native. |
| multik-openblas | Native implementation backed by OpenBLAS via C++/JNI. JVM and desktop native (macOS, Linux, Windows). |
multik-core provides ndarray types, creation functions, and basic operations.
For linear algebra, statistics, and math engines, add an engine dependency —
multik-default, multik-kotlin, or multik-openblas.
Engine dependencies transitively include multik-core.
build.gradle.kts:
repositories {
mavenCentral()
}
dependencies {
implementation("org.jetbrains.kotlinx:multik-default:$multikVersion")
}build.gradle:
repositories {
mavenCentral()
}
dependencies {
implementation "org.jetbrains.kotlinx:multik-default:$multikVersion"
}kotlin {
sourceSets {
commonMain {
dependencies {
implementation("org.jetbrains.kotlinx:multik-default:$multikVersion")
}
}
}
}Install Kotlin kernel for Jupyter or just visit to Datalore.
Import stable multik version into notebook:
%use multik
| Platform | multik-core |
multik-kotlin |
multik-openblas |
multik-default |
|---|---|---|---|---|
| JVM | ✅ | ✅ | ✅ | ✅ |
| JS | ✅ | ✅ | — | ✅ |
| WasmJS | ✅ | ✅ | — | ✅ |
| linuxX64 | ✅ | ✅ | ✅ | ✅ |
| mingwX64 | ✅ | ✅ | ✅ | ✅ |
| macosX64 | ✅ | ✅ | ✅ | ✅ |
| macosArm64 | ✅ | ✅ | ✅ | ✅ |
| iosArm64 | ✅ | ✅ | — | ✅ |
| iosX64 | ✅ | ✅ | — | ✅ |
| iosSimulatorArm64 | ✅ | ✅ | — | ✅ |
[!IMPORTANT]
- On Ubuntu 18.04 and older,
multik-openblasdoesn't work due to older versions of glibc.multik-openblasfor desktop native targets (linuxX64, mingwX64, macosX64, macosArm64) is experimental and unstable.- JVM target
multik-openblasfor Android only supports arm64-v8a processors.
Visit Multik documentation for a detailed feature overview.
val a = mk.ndarray(mk[1, 2, 3])
/* [1, 2, 3] */
val b = mk.ndarray(mk[mk[1.5, 2.1, 3.0], mk[4.0, 5.0, 6.0]])
/*
[[1.5, 2.1, 3.0],
[4.0, 5.0, 6.0]]
*/
val c = mk.ndarray(mk[mk[mk[1.5f, 2f, 3f], mk[4f, 5f, 6f]], mk[mk[3f, 2f, 1f], mk[4f, 5f, 6f]]])
/*
[[[1.5, 2.0, 3.0],
[4.0, 5.0, 6.0]],
[[3.0, 2.0, 1.0],
[4.0, 5.0, 6.0]]]
*/
mk.zeros<Double>(3, 4) // create an array of zeros
/*
[[0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0]]
*/
mk.ndarray<Float, D2>(setOf(30f, 2f, 13f, 12f), intArrayOf(2, 2)) // create an array from a collection
/*
[[30.0, 2.0],
[13.0, 12.0]]
*/
val d = mk.ndarray(
doubleArrayOf(1.0, 1.3, 3.0, 4.0, 9.5, 5.0),
2,
3
) // create an array of shape(2, 3) from a primitive array
/*
[[1.0, 1.3, 3.0],
[4.0, 9.5, 5.0]]
*/
mk.d3array(2, 2, 3) { it * it } // create an array of 3 dimension
/*
[[[0, 1, 4],
[9, 16, 25]],
[[36, 49, 64],
[81, 100, 121]]]
*/
mk.d2arrayIndices(3, 3) { i, j -> ComplexFloat(i, j) }
/*
[[0.0+(0.0)i, 0.0+(1.0)i, 0.0+(2.0)i],
[1.0+(0.0)i, 1.0+(1.0)i, 1.0+(2.0)i],
[2.0+(0.0)i, 2.0+(1.0)i, 2.0+(2.0)i]]
*/
mk.arange<Long>(10, 25, 5) // create an array with elements in the interval [10, 25) with step 5
/* [10, 15, 20] */
mk.linspace<Double>(0, 2, 9) // create an array of 9 elements in the interval [0, 2]
/* [0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0] */
val e = mk.identity<Double>(3) // create an identity array of shape (3, 3)
/*
[[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0]]
*/
val diag = mk.diagonal(mk[2, 4, 8]) // create a diagonal array
/*
[[2, 0, 0],
[0, 4, 0],
[0, 0, 8]]
*/a.shape // Array dimensions
a.size // Size of array
a.dim // object Dimension
a.dim.d // number of array dimensions
a.dtype // Data type of array elementsval f = b - d // subtraction
/*
[[0.5, 0.8, 0.0],
[0.0, -4.5, 1.0]]
*/
d + f // addition
/*
[[1.5, 2.1, 3.0],
[4.0, 5.0, 6.0]]
*/
b / d // division
/*
[[1.5, 1.6153846153846154, 1.0],
[1.0, 0.5263157894736842, 1.2]]
*/
f * d // multiplication
/*
[[0.5, 1.04, 0.0],
[0.0, -42.75, 5.0]]
*/See documentation for other methods of mathematics, linear algebra, statistics.
a.sin() // element-wise sin, equivalent to mk.math.sin(a)
a.cos() // element-wise cos, equivalent to mk.math.cos(a)
b.log() // element-wise natural logarithm, equivalent to mk.math.log(b)
b.exp() // element-wise exp, equivalent to mk.math.exp(b)
d dot e // dot product, equivalent to mk.linalg.dot(d, e)
mk.math.sum(c) // array-wise sum
mk.math.min(c) // array-wise minimum elements
mk.math.maxD3(c, axis = 0) // maximum value of an array along axis 0
mk.math.cumSum(b, axis = 1) // cumulative sum of the elements
mk.stat.mean(a) // mean
mk.stat.median(b) // medianval f = a.copy() // create a copy of the array and its data
val h = b.deepCopy() // create a copy of the array and copy the meaningful datac.filter { it < 3 } // select all elements less than 3
b.map { (it * it).toInt() } // return squares
c.groupNDArrayBy { it % 2 } // group elements by condition
c.sorted() // sort elementsa[2] // select the element at the 2 index
b[1, 2] // select the element at row 1 column 2
b[1] // select row 1
b[0..1, 1] // select elements at rows 0 to 1 in column 1
b[0, 0..2..1] // select elements at row 0 in columns 0 to 2 with step 1
for (el in b) {
print("$el, ") // 1.5, 2.1, 3.0, 4.0, 5.0, 6.0,
}
// for n-dimensional
val q = b.asDNArray()
for (index in q.multiIndices) {
print("${q[index]}, ") // 1.5, 2.1, 3.0, 4.0, 5.0, 6.0,
}val a = mk.linspace<Float>(0, 1, 10)
/*
a = [0.0, 0.1111111111111111, 0.2222222222222222, 0.3333333333333333, 0.4444444444444444, 0.5555555555555556,
0.6666666666666666, 0.7777777777777777, 0.8888888888888888, 1.0]
*/
val b = mk.linspace<Float>(8, 9, 10)
/*
b = [8.0, 8.11111111111111, 8.222222222222221, 8.333333333333334, 8.444444444444445, 8.555555555555555,
8.666666666666666, 8.777777777777779, 8.88888888888889, 9.0]
*/
a.inplace {
math {
(this - b) * b
abs()
}
}
// a = [64.0, 64.88888, 65.77778, 66.66666, 67.55556, 68.44444, 69.333336, 70.22222, 71.111115, 72.0]Requires:
JAVA_HOME environment variable setgcc, g++, gfortran version 8 or higher (must be the same version)./gradlew assemble./gradlew assemble -x build_cmake./gradlew :multik-core:build./gradlew :multik-core:jvmTestSee CONTRIBUTING.md for guidelines on submitting issues, pull requests, and building the project.
Multik is licensed under the Apache License 2.0.