diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4266c5b70..cdc82753c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@
- Multiplatform integration
- Integration for any Field element
- Extended operations for ND4J fields
+- Jupyter Notebook integration module (kmath-jupyter)
### Changed
- Exponential operations merged with hyperbolic functions
diff --git a/build.gradle.kts b/build.gradle.kts
index 506f51a0e..760bf1aee 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,5 +1,6 @@
plugins {
id("ru.mipt.npm.gradle.project")
+ kotlin("jupyter.api") apply false
}
allprojects {
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 517ec0dc9..5b44e660d 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
@@ -18,11 +18,14 @@ import space.kscience.kmath.misc.UnstableKMathAPI
public object MathMLSyntaxRenderer : SyntaxRenderer {
public override fun render(node: MathSyntax, output: Appendable) {
output.append("")
}
- private fun render0(node: MathSyntax, output: Appendable): Unit = output.run {
+ /**
+ * Renders a part of syntax returning a correct MathML tag not the whole MathML instance.
+ */
+ public fun renderPart(node: MathSyntax, output: Appendable): Unit = output.run {
fun tag(tagName: String, vararg attr: Pair, block: () -> Unit = {}) {
append('<')
append(tagName)
@@ -47,7 +50,7 @@ public object MathMLSyntaxRenderer : SyntaxRenderer {
append('>')
}
- fun render(syntax: MathSyntax) = render0(syntax, output)
+ fun render(syntax: MathSyntax) = renderPart(syntax, output)
when (node) {
is NumberSyntax -> tag("mn") { append(node.string) }
diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api
index 6b300123c..82b44d275 100644
--- a/kmath-core/api/kmath-core.api
+++ b/kmath-core/api/kmath-core.api
@@ -272,6 +272,8 @@ public final class space/kscience/kmath/expressions/MstExtendedField : space/ksc
public fun sin (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary;
public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object;
public fun sinh (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary;
+ public synthetic fun sqrt (Ljava/lang/Object;)Ljava/lang/Object;
+ public fun sqrt (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST;
public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object;
public fun tan (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary;
public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object;
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 32a7efc1e..53124b777 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
@@ -135,6 +135,7 @@ public object MstExtendedField : ExtendedField, NumericAlgebra {
public override fun acosh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ACOSH_OPERATION)(arg)
public override fun atanh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ATANH_OPERATION)(arg)
public override fun add(a: MST, b: MST): MST.Binary = MstField.add(a, b)
+ public override fun sqrt(arg: MST): MST = unaryOperationFunction(PowerOperations.SQRT_OPERATION)(arg)
public override fun scale(a: MST, value: Double): MST =
binaryOperation(GroupOperations.PLUS_OPERATION, a, number(value))
diff --git a/kmath-jupyter/build.gradle.kts b/kmath-jupyter/build.gradle.kts
new file mode 100644
index 000000000..815cb9b8c
--- /dev/null
+++ b/kmath-jupyter/build.gradle.kts
@@ -0,0 +1,19 @@
+plugins {
+ id("ru.mipt.npm.gradle.jvm")
+ kotlin("jupyter.api")
+}
+
+dependencies {
+ api(project(":kmath-ast"))
+ api(project(":kmath-complex"))
+ api(project(":kmath-for-real"))
+ implementation("org.jetbrains.kotlinx:kotlinx-html-jvm:0.7.3")
+}
+
+readme {
+ maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE
+}
+
+kotlin.sourceSets.all {
+ languageSettings.useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI")
+}
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
new file mode 100644
index 000000000..e13c92f75
--- /dev/null
+++ b/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt
@@ -0,0 +1,120 @@
+package space.kscience.kmath.jupyter
+
+import kotlinx.html.Unsafe
+import kotlinx.html.div
+import kotlinx.html.stream.createHTML
+import kotlinx.html.unsafe
+import org.jetbrains.kotlinx.jupyter.api.DisplayResult
+import org.jetbrains.kotlinx.jupyter.api.HTML
+import org.jetbrains.kotlinx.jupyter.api.annotations.JupyterLibrary
+import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration
+import space.kscience.kmath.expressions.MST
+import space.kscience.kmath.ast.rendering.FeaturedMathRendererWithPostProcess
+import space.kscience.kmath.ast.rendering.MathMLSyntaxRenderer
+import space.kscience.kmath.ast.rendering.renderWithStringBuilder
+import space.kscience.kmath.complex.Complex
+import space.kscience.kmath.nd.Structure2D
+import space.kscience.kmath.operations.GroupOperations
+import space.kscience.kmath.operations.RingOperations
+import space.kscience.kmath.structures.Buffer
+import space.kscience.kmath.structures.asSequence
+
+@JupyterLibrary
+internal class KMathJupyter : JupyterIntegration() {
+ private val mathRender = FeaturedMathRendererWithPostProcess.Default
+ private val syntaxRender = MathMLSyntaxRenderer
+
+ override fun Builder.onLoaded() {
+ import(
+ "space.kscience.kmath.ast.*",
+ "space.kscience.kmath.ast.rendering.*",
+ "space.kscience.kmath.operations.*",
+ "space.kscience.kmath.expressions.*",
+ "space.kscience.kmath.misc.*",
+ "space.kscience.kmath.real.*",
+ )
+
+ fun MST.toDisplayResult(): DisplayResult = HTML(createHTML().div {
+ unsafe {
+ +syntaxRender.renderWithStringBuilder(mathRender.render(this@toDisplayResult))
+ }
+ })
+
+ render { it.toDisplayResult() }
+ render { MST.Numeric(it).toDisplayResult() }
+
+ fun Unsafe.appendCellValue(it: Any?) {
+ when (it) {
+ is Number -> {
+ val s = StringBuilder()
+ syntaxRender.renderPart(mathRender.render(MST.Numeric(it)), s)
+ +s.toString()
+ }
+ is MST -> {
+ val s = StringBuilder()
+ syntaxRender.renderPart(mathRender.render(it), s)
+ +s.toString()
+ }
+ else -> {
+ +""
+ +it.toString()
+ +""
+ }
+ }
+ }
+
+ render> { structure ->
+ HTML(createHTML().div {
+ unsafe {
+ +""
+ }
+ })
+ }
+
+ render> { buffer ->
+ HTML(createHTML().div {
+ unsafe {
+ +""
+ }
+ })
+ }
+
+ render {
+ MST.Binary(
+ operation = GroupOperations.PLUS_OPERATION,
+ left = MST.Numeric(it.re),
+ right = MST.Binary(RingOperations.TIMES_OPERATION, MST.Numeric(it.im), MST.Symbolic("i")),
+ ).toDisplayResult()
+ }
+ }
+}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index ca36168e1..b7613d589 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -17,6 +17,9 @@ pluginManagement {
id("ru.mipt.npm.gradle.project") version toolsVersion
id("ru.mipt.npm.gradle.mpp") version toolsVersion
id("ru.mipt.npm.gradle.jvm") version toolsVersion
+ kotlin("jupyter.api") version "0.9.0.12"
+ kotlin("jvm") version kotlinVersion
+ kotlin("plugin.allopen") version kotlinVersion
}
}
@@ -39,6 +42,7 @@ include(
":kmath-ast",
":kmath-ejml",
":kmath-kotlingrad",
+ ":kmath-jupyter",
":examples",
":benchmarks"
)