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("") - render0(node, output) + renderPart(node, output) 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 { + +"" + +"" + +"" + +"" + structure.rows.forEach { row -> + +"" + row.asSequence().forEach { + +"" + appendCellValue(it) + +"" + } + +"" + } + +"" + +"" + +"" + +"" + } + }) + } + + render> { buffer -> + HTML(createHTML().div { + unsafe { + +"" + +"" + +"" + +"" + buffer.asSequence().forEach { + +"" + +"" + appendCellValue(it) + +"" + +"" + } + +"" + +"" + +"" + +"" + } + }) + } + + 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" )