kmath/kmath-ast/index.html

136 lines
42 KiB
HTML

<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" charset="UTF-8">
<title>kmath-ast</title>
</head><body><link href="../images/logo-icon.svg" rel="icon" type="image/svg"><script>var pathToRoot = "../";</script>
<script type="text/javascript" src="../scripts/sourceset_dependencies.js" async></script><link href="../styles/style.css" rel="Stylesheet"><link href="../styles/jetbrains-mono.css" rel="Stylesheet"><link href="../styles/main.css" rel="Stylesheet"><link href="../styles/prism.css" rel="Stylesheet"><link href="../styles/logo-styles.css" rel="Stylesheet"><script type="text/javascript" src="../scripts/clipboard.js" async></script><script type="text/javascript" src="../scripts/navigation-loader.js" async></script><script type="text/javascript" src="../scripts/platform-content-handler.js" async></script><script type="text/javascript" src="../scripts/main.js" defer></script><script type="text/javascript" src="../scripts/prism.js" async></script><script>const storage = localStorage.getItem("dokka-dark-mode")
const savedDarkMode = storage ? JSON.parse(storage) : false
if(savedDarkMode === true){
document.getElementsByTagName("html")[0].classList.add("theme-dark")
}</script>
<div class="navigation-wrapper" id="navigation-wrapper">
<div id="leftToggler"><span class="icon-toggler"></span></div>
<div class="library-name"><a href="../index.html"><span>kmath</span></a></div>
<div></div>
<div class="pull-right d-flex">
<div class="filter-section" id="filter-section"><button class="platform-tag platform-selector common-like" data-active="" data-filter=":kmath-ast:dokkaHtmlPartial/commonMain">common</button><button class="platform-tag platform-selector js-like" data-active="" data-filter=":kmath-ast:dokkaHtmlPartial/jsMain">js</button><button class="platform-tag platform-selector jvm-like" data-active="" data-filter=":kmath-ast:dokkaHtmlPartial/jvmMain">jvm</button></div>
<button id="theme-toggle-button"><span id="theme-toggle"></span></button>
<div id="searchBar"></div>
</div>
</div>
<div id="container">
<div id="leftColumn">
<div id="sideMenu"></div>
</div>
<div id="main">
<div class="main-content" id="content" pageids="kmath-ast::////PointingToDeclaration//-1763828843">
<div class="breadcrumbs"></div>
<div class="cover ">
<h1 class="cover"><span><span>kmath-ast</span></span></h1>
<div class="platform-hinted UnderCoverText with-platform-tabs" data-platform-hinted="data-platform-hinted">
<div class="platform-bookmarks-row" data-toggle-list="data-toggle-list"><button class="platform-bookmark common-like" data-filterable-current=":kmath-ast:dokkaHtmlPartial/commonMain" data-filterable-set=":kmath-ast:dokkaHtmlPartial/commonMain" data-active="" data-toggle=":kmath-ast:dokkaHtmlPartial/commonMain">common</button><button class="platform-bookmark js-like" data-filterable-current=":kmath-ast:dokkaHtmlPartial/jsMain" data-filterable-set=":kmath-ast:dokkaHtmlPartial/jsMain" data-toggle=":kmath-ast:dokkaHtmlPartial/jsMain">js</button><button class="platform-bookmark jvm-like" data-filterable-current=":kmath-ast:dokkaHtmlPartial/jvmMain" data-filterable-set=":kmath-ast:dokkaHtmlPartial/jvmMain" data-toggle=":kmath-ast:dokkaHtmlPartial/jvmMain">jvm</button></div>
<div class="content sourceset-depenent-content" data-active="" data-togglable=":kmath-ast:dokkaHtmlPartial/commonMain"><p class="paragraph">Extensions to MST API: transformations, dynamic compilation and visualization.</p><ul><li><p class="paragraph">src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt : Expression language and its parser</p></li><li><p class="paragraph">src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt : Dynamic MST to JVM bytecode compiler</p></li><li><p class="paragraph">src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt : Dynamic MST to JS compiler</p></li><li><p class="paragraph">src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt : Extendable MST rendering</p></li></ul><h2 class=""> Artifact:</h2><p class="paragraph">The Maven coordinates of this project are <code class="lang-kotlin">space.kscience:kmath-ast:0.3.0</code>.</p><p class="paragraph"><strong>Gradle Groovy:</strong></p><div class="sample-container"><pre><code class="block lang-groovy" theme="idea">repositories {<br> maven { url 'https://repo.kotlin.link' }<br> mavenCentral()<br>}<br><br>dependencies {<br> implementation 'space.kscience:kmath-ast:0.3.0'<br>}</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph"><strong>Gradle Kotlin DSL:</strong></p><div class="sample-container"><pre><code class="block lang-kotlin" theme="idea">repositories {<br> maven("https://repo.kotlin.link")<br> mavenCentral()<br>}<br><br>dependencies {<br> implementation("space.kscience:kmath-ast:0.3.0")<br>}</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><h2 class=""> Parsing expressions</h2><p class="paragraph">In this module there is a parser from human-readable strings like <code class="lang-kotlin">"x^3-x+3"</code> (in the more specific reference/ArithmeticsEvaluator.g4) to MST instances.</p><p class="paragraph">Supported literals:</p><ol><li><p class="paragraph">Constants and variables (consist of latin letters, digits and underscores, can't start with digit): <code class="lang-kotlin">x</code>, <code class="lang-kotlin">_Abc2</code>.</p></li><li><p class="paragraph">Numbers: <code class="lang-kotlin">123</code>, <code class="lang-kotlin">1.02</code>, <code class="lang-kotlin">1e10</code>, <code class="lang-kotlin">1e-10</code>, <code class="lang-kotlin">1.0e+3</code>—all parsed either as <code class="lang-kotlin">kotlin.Long</code> or <code class="lang-kotlin">kotlin.Double</code>.</p></li></ol><p class="paragraph">Supported binary operators (from the highest precedence to the lowest one):</p><ol><li><p class="paragraph"><code class="lang-kotlin">^</code></p></li><li><p class="paragraph"><code class="lang-kotlin">*</code>, <code class="lang-kotlin">/</code></p></li><li><p class="paragraph"><code class="lang-kotlin">+</code>, <code class="lang-kotlin">-</code></p></li></ol><p class="paragraph">Supported unary operator:</p><ol><li><p class="paragraph"><code class="lang-kotlin">-</code>, e.&nbsp;g. <code class="lang-kotlin">-x</code></p></li></ol><p class="paragraph">Arbitrary unary and binary functions are also supported: names consist of latin letters, digits and underscores, can't start with digit. Examples:</p><ol><li><p class="paragraph"><code class="lang-kotlin">sin(x)</code></p></li><li><p class="paragraph"><code class="lang-kotlin">add(x, y)</code></p></li></ol><h2 class=""> Dynamic expression code generation</h2><h3 class=""> On JVM</h3><p class="paragraph"><code class="lang-kotlin">kmath-ast</code> JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds a special implementation of <code class="lang-kotlin">Expression&lt;T&gt;</code> with implemented <code class="lang-kotlin">invoke</code> function.</p><p class="paragraph">For example, the following code:</p><div class="sample-container"><pre><code class="block lang-kotlin" theme="idea">import space.kscience.kmath.asm.compileToExpression<br>import space.kscience.kmath.operations.DoubleField<br><br>"x^3-x+3".parseMath().compileToExpression(DoubleField)</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph">… leads to generation of bytecode, which can be decompiled to the following Java class:</p><div class="sample-container"><pre><code class="block lang-java" theme="idea">import java.util.*;<br>import kotlin.jvm.functions.*;<br>import space.kscience.kmath.asm.internal.*;<br>import space.kscience.kmath.complex.*;<br>import space.kscience.kmath.expressions.*;<br><br>public final class CompiledExpression_45045_0 implements Expression&lt;Complex&gt; {<br> private final Object[] constants;<br><br> public Complex invoke(Map&lt;Symbol, ? extends Complex&gt; arguments) {<br> Complex var2 = (Complex)MapIntrinsics.getOrFail(arguments, "x");<br> return (Complex)((Function2)this.constants[0]).invoke(var2, (Complex)this.constants[1]);<br> }<br>}</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph">For <code class="lang-kotlin">LongRing</code>, <code class="lang-kotlin">IntRing</code>, and <code class="lang-kotlin">DoubleField</code> specialization is supported for better performance:</p><div class="sample-container"><pre><code class="block lang-java" theme="idea">import java.util.*;<br>import space.kscience.kmath.asm.internal.*;<br>import space.kscience.kmath.expressions.*;<br><br>public final class CompiledExpression_-386104628_0 implements DoubleExpression {<br> private final SymbolIndexer indexer;<br><br> public SymbolIndexer getIndexer() {<br> return this.indexer;<br> }<br><br> public double invoke(double[] arguments) {<br> double var2 = arguments[0];<br> return Math.pow(var2, 3.0D) - var2 + 3.0D;<br> }<br><br> public final Double invoke(Map&lt;Symbol, ? extends Double&gt; arguments) {<br> double var2 = ((Double)MapIntrinsics.getOrFail(arguments, "x")).doubleValue();<br> return Math.pow(var2, 3.0D) - var2 + 3.0D;<br> }<br>}</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph">Setting JVM system property <code class="lang-kotlin">space.kscience.kmath.ast.dump.generated.classes</code> to <code class="lang-kotlin">1</code> makes the translator dump class files to program's working directory, so they can be reviewed manually.</p><h4 class=""> Limitations</h4><ul><li><p class="paragraph">The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class loading overhead.</p></li><li><p class="paragraph">This API is not supported by non-dynamic JVM implementations like TeaVM or GraalVM Native Image because they may not support class loaders.</p></li></ul><h3 class=""> On JS</h3><p class="paragraph">A similar feature is also available on JS.</p><div class="sample-container"><pre><code class="block lang-kotlin" theme="idea">import space.kscience.kmath.expressions.Symbol.Companion.x<br>import space.kscience.kmath.expressions.*<br>import space.kscience.kmath.operations.*<br>import space.kscience.kmath.estree.*<br><br>MstField { x + 2 }.compileToExpression(DoubleField)</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph">The code above returns expression implemented with such a JS function:</p><div class="sample-container"><pre><code class="block lang-js" theme="idea">var executable = function (constants, arguments) {<br> return constants[1](constants[0](arguments, "x"), 2);<br>};</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph">JS also supports experimental expression optimization with <a href="https://webassembly.org/">WebAssembly</a> IR generation. Currently, only expressions inside <code class="lang-kotlin">DoubleField</code> and <code class="lang-kotlin">IntRing</code> are supported.</p><div class="sample-container"><pre><code class="block lang-kotlin" theme="idea">import space.kscience.kmath.expressions.Symbol.Companion.x<br>import space.kscience.kmath.expressions.*<br>import space.kscience.kmath.operations.*<br>import space.kscience.kmath.wasm.*<br><br>MstField { x + 2 }.compileToExpression(DoubleField)</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph">An example of emitted Wasm IR in the form of WAT:</p><div class="sample-container"><pre><code class="block lang-lisp" theme="idea">(func \$executable (param \$0 f64) (result f64)<br> (f64.add<br> (local.get \$0)<br> (f64.const 2)<br> )<br>)</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><h4 class=""> Limitations</h4><ul><li><p class="paragraph">ESTree expression compilation uses <code class="lang-kotlin">eval</code> which can be unavailable in several environments.</p></li><li><p class="paragraph">WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/).</p></li></ul><h2 class=""> Rendering expressions</h2><p class="paragraph">kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax.</p><p class="paragraph">Example usage:</p><div class="sample-container"><pre><code class="block lang-kotlin" theme="idea">import space.kscience.kmath.ast.*<br>import space.kscience.kmath.ast.rendering.*<br>import space.kscience.kmath.misc.*</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div></div><div class="content sourceset-depenent-content" data-togglable=":kmath-ast:dokkaHtmlPartial/jsMain"><p class="paragraph">Extensions to MST API: transformations, dynamic compilation and visualization.</p><ul><li><p class="paragraph">src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt : Expression language and its parser</p></li><li><p class="paragraph">src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt : Dynamic MST to JVM bytecode compiler</p></li><li><p class="paragraph">src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt : Dynamic MST to JS compiler</p></li><li><p class="paragraph">src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt : Extendable MST rendering</p></li></ul><h2 class=""> Artifact:</h2><p class="paragraph">The Maven coordinates of this project are <code class="lang-kotlin">space.kscience:kmath-ast:0.3.0</code>.</p><p class="paragraph"><strong>Gradle Groovy:</strong></p><div class="sample-container"><pre><code class="block lang-groovy" theme="idea">repositories {<br> maven { url 'https://repo.kotlin.link' }<br> mavenCentral()<br>}<br><br>dependencies {<br> implementation 'space.kscience:kmath-ast:0.3.0'<br>}</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph"><strong>Gradle Kotlin DSL:</strong></p><div class="sample-container"><pre><code class="block lang-kotlin" theme="idea">repositories {<br> maven("https://repo.kotlin.link")<br> mavenCentral()<br>}<br><br>dependencies {<br> implementation("space.kscience:kmath-ast:0.3.0")<br>}</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><h2 class=""> Parsing expressions</h2><p class="paragraph">In this module there is a parser from human-readable strings like <code class="lang-kotlin">"x^3-x+3"</code> (in the more specific reference/ArithmeticsEvaluator.g4) to MST instances.</p><p class="paragraph">Supported literals:</p><ol><li><p class="paragraph">Constants and variables (consist of latin letters, digits and underscores, can't start with digit): <code class="lang-kotlin">x</code>, <code class="lang-kotlin">_Abc2</code>.</p></li><li><p class="paragraph">Numbers: <code class="lang-kotlin">123</code>, <code class="lang-kotlin">1.02</code>, <code class="lang-kotlin">1e10</code>, <code class="lang-kotlin">1e-10</code>, <code class="lang-kotlin">1.0e+3</code>—all parsed either as <code class="lang-kotlin">kotlin.Long</code> or <code class="lang-kotlin">kotlin.Double</code>.</p></li></ol><p class="paragraph">Supported binary operators (from the highest precedence to the lowest one):</p><ol><li><p class="paragraph"><code class="lang-kotlin">^</code></p></li><li><p class="paragraph"><code class="lang-kotlin">*</code>, <code class="lang-kotlin">/</code></p></li><li><p class="paragraph"><code class="lang-kotlin">+</code>, <code class="lang-kotlin">-</code></p></li></ol><p class="paragraph">Supported unary operator:</p><ol><li><p class="paragraph"><code class="lang-kotlin">-</code>, e.&nbsp;g. <code class="lang-kotlin">-x</code></p></li></ol><p class="paragraph">Arbitrary unary and binary functions are also supported: names consist of latin letters, digits and underscores, can't start with digit. Examples:</p><ol><li><p class="paragraph"><code class="lang-kotlin">sin(x)</code></p></li><li><p class="paragraph"><code class="lang-kotlin">add(x, y)</code></p></li></ol><h2 class=""> Dynamic expression code generation</h2><h3 class=""> On JVM</h3><p class="paragraph"><code class="lang-kotlin">kmath-ast</code> JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds a special implementation of <code class="lang-kotlin">Expression&lt;T&gt;</code> with implemented <code class="lang-kotlin">invoke</code> function.</p><p class="paragraph">For example, the following code:</p><div class="sample-container"><pre><code class="block lang-kotlin" theme="idea">import space.kscience.kmath.asm.compileToExpression<br>import space.kscience.kmath.operations.DoubleField<br><br>"x^3-x+3".parseMath().compileToExpression(DoubleField)</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph">… leads to generation of bytecode, which can be decompiled to the following Java class:</p><div class="sample-container"><pre><code class="block lang-java" theme="idea">import java.util.*;<br>import kotlin.jvm.functions.*;<br>import space.kscience.kmath.asm.internal.*;<br>import space.kscience.kmath.complex.*;<br>import space.kscience.kmath.expressions.*;<br><br>public final class CompiledExpression_45045_0 implements Expression&lt;Complex&gt; {<br> private final Object[] constants;<br><br> public Complex invoke(Map&lt;Symbol, ? extends Complex&gt; arguments) {<br> Complex var2 = (Complex)MapIntrinsics.getOrFail(arguments, "x");<br> return (Complex)((Function2)this.constants[0]).invoke(var2, (Complex)this.constants[1]);<br> }<br>}</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph">For <code class="lang-kotlin">LongRing</code>, <code class="lang-kotlin">IntRing</code>, and <code class="lang-kotlin">DoubleField</code> specialization is supported for better performance:</p><div class="sample-container"><pre><code class="block lang-java" theme="idea">import java.util.*;<br>import space.kscience.kmath.asm.internal.*;<br>import space.kscience.kmath.expressions.*;<br><br>public final class CompiledExpression_-386104628_0 implements DoubleExpression {<br> private final SymbolIndexer indexer;<br><br> public SymbolIndexer getIndexer() {<br> return this.indexer;<br> }<br><br> public double invoke(double[] arguments) {<br> double var2 = arguments[0];<br> return Math.pow(var2, 3.0D) - var2 + 3.0D;<br> }<br><br> public final Double invoke(Map&lt;Symbol, ? extends Double&gt; arguments) {<br> double var2 = ((Double)MapIntrinsics.getOrFail(arguments, "x")).doubleValue();<br> return Math.pow(var2, 3.0D) - var2 + 3.0D;<br> }<br>}</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph">Setting JVM system property <code class="lang-kotlin">space.kscience.kmath.ast.dump.generated.classes</code> to <code class="lang-kotlin">1</code> makes the translator dump class files to program's working directory, so they can be reviewed manually.</p><h4 class=""> Limitations</h4><ul><li><p class="paragraph">The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class loading overhead.</p></li><li><p class="paragraph">This API is not supported by non-dynamic JVM implementations like TeaVM or GraalVM Native Image because they may not support class loaders.</p></li></ul><h3 class=""> On JS</h3><p class="paragraph">A similar feature is also available on JS.</p><div class="sample-container"><pre><code class="block lang-kotlin" theme="idea">import space.kscience.kmath.expressions.Symbol.Companion.x<br>import space.kscience.kmath.expressions.*<br>import space.kscience.kmath.operations.*<br>import space.kscience.kmath.estree.*<br><br>MstField { x + 2 }.compileToExpression(DoubleField)</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph">The code above returns expression implemented with such a JS function:</p><div class="sample-container"><pre><code class="block lang-js" theme="idea">var executable = function (constants, arguments) {<br> return constants[1](constants[0](arguments, "x"), 2);<br>};</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph">JS also supports experimental expression optimization with <a href="https://webassembly.org/">WebAssembly</a> IR generation. Currently, only expressions inside <code class="lang-kotlin">DoubleField</code> and <code class="lang-kotlin">IntRing</code> are supported.</p><div class="sample-container"><pre><code class="block lang-kotlin" theme="idea">import space.kscience.kmath.expressions.Symbol.Companion.x<br>import space.kscience.kmath.expressions.*<br>import space.kscience.kmath.operations.*<br>import space.kscience.kmath.wasm.*<br><br>MstField { x + 2 }.compileToExpression(DoubleField)</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph">An example of emitted Wasm IR in the form of WAT:</p><div class="sample-container"><pre><code class="block lang-lisp" theme="idea">(func \$executable (param \$0 f64) (result f64)<br> (f64.add<br> (local.get \$0)<br> (f64.const 2)<br> )<br>)</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><h4 class=""> Limitations</h4><ul><li><p class="paragraph">ESTree expression compilation uses <code class="lang-kotlin">eval</code> which can be unavailable in several environments.</p></li><li><p class="paragraph">WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/).</p></li></ul><h2 class=""> Rendering expressions</h2><p class="paragraph">kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax.</p><p class="paragraph">Example usage:</p><div class="sample-container"><pre><code class="block lang-kotlin" theme="idea">import space.kscience.kmath.ast.*<br>import space.kscience.kmath.ast.rendering.*<br>import space.kscience.kmath.misc.*</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div></div><div class="content sourceset-depenent-content" data-togglable=":kmath-ast:dokkaHtmlPartial/jvmMain"><p class="paragraph">Extensions to MST API: transformations, dynamic compilation and visualization.</p><ul><li><p class="paragraph">src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt : Expression language and its parser</p></li><li><p class="paragraph">src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt : Dynamic MST to JVM bytecode compiler</p></li><li><p class="paragraph">src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt : Dynamic MST to JS compiler</p></li><li><p class="paragraph">src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt : Extendable MST rendering</p></li></ul><h2 class=""> Artifact:</h2><p class="paragraph">The Maven coordinates of this project are <code class="lang-kotlin">space.kscience:kmath-ast:0.3.0</code>.</p><p class="paragraph"><strong>Gradle Groovy:</strong></p><div class="sample-container"><pre><code class="block lang-groovy" theme="idea">repositories {<br> maven { url 'https://repo.kotlin.link' }<br> mavenCentral()<br>}<br><br>dependencies {<br> implementation 'space.kscience:kmath-ast:0.3.0'<br>}</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph"><strong>Gradle Kotlin DSL:</strong></p><div class="sample-container"><pre><code class="block lang-kotlin" theme="idea">repositories {<br> maven("https://repo.kotlin.link")<br> mavenCentral()<br>}<br><br>dependencies {<br> implementation("space.kscience:kmath-ast:0.3.0")<br>}</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><h2 class=""> Parsing expressions</h2><p class="paragraph">In this module there is a parser from human-readable strings like <code class="lang-kotlin">"x^3-x+3"</code> (in the more specific reference/ArithmeticsEvaluator.g4) to MST instances.</p><p class="paragraph">Supported literals:</p><ol><li><p class="paragraph">Constants and variables (consist of latin letters, digits and underscores, can't start with digit): <code class="lang-kotlin">x</code>, <code class="lang-kotlin">_Abc2</code>.</p></li><li><p class="paragraph">Numbers: <code class="lang-kotlin">123</code>, <code class="lang-kotlin">1.02</code>, <code class="lang-kotlin">1e10</code>, <code class="lang-kotlin">1e-10</code>, <code class="lang-kotlin">1.0e+3</code>—all parsed either as <code class="lang-kotlin">kotlin.Long</code> or <code class="lang-kotlin">kotlin.Double</code>.</p></li></ol><p class="paragraph">Supported binary operators (from the highest precedence to the lowest one):</p><ol><li><p class="paragraph"><code class="lang-kotlin">^</code></p></li><li><p class="paragraph"><code class="lang-kotlin">*</code>, <code class="lang-kotlin">/</code></p></li><li><p class="paragraph"><code class="lang-kotlin">+</code>, <code class="lang-kotlin">-</code></p></li></ol><p class="paragraph">Supported unary operator:</p><ol><li><p class="paragraph"><code class="lang-kotlin">-</code>, e.&nbsp;g. <code class="lang-kotlin">-x</code></p></li></ol><p class="paragraph">Arbitrary unary and binary functions are also supported: names consist of latin letters, digits and underscores, can't start with digit. Examples:</p><ol><li><p class="paragraph"><code class="lang-kotlin">sin(x)</code></p></li><li><p class="paragraph"><code class="lang-kotlin">add(x, y)</code></p></li></ol><h2 class=""> Dynamic expression code generation</h2><h3 class=""> On JVM</h3><p class="paragraph"><code class="lang-kotlin">kmath-ast</code> JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds a special implementation of <code class="lang-kotlin">Expression&lt;T&gt;</code> with implemented <code class="lang-kotlin">invoke</code> function.</p><p class="paragraph">For example, the following code:</p><div class="sample-container"><pre><code class="block lang-kotlin" theme="idea">import space.kscience.kmath.asm.compileToExpression<br>import space.kscience.kmath.operations.DoubleField<br><br>"x^3-x+3".parseMath().compileToExpression(DoubleField)</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph">… leads to generation of bytecode, which can be decompiled to the following Java class:</p><div class="sample-container"><pre><code class="block lang-java" theme="idea">import java.util.*;<br>import kotlin.jvm.functions.*;<br>import space.kscience.kmath.asm.internal.*;<br>import space.kscience.kmath.complex.*;<br>import space.kscience.kmath.expressions.*;<br><br>public final class CompiledExpression_45045_0 implements Expression&lt;Complex&gt; {<br> private final Object[] constants;<br><br> public Complex invoke(Map&lt;Symbol, ? extends Complex&gt; arguments) {<br> Complex var2 = (Complex)MapIntrinsics.getOrFail(arguments, "x");<br> return (Complex)((Function2)this.constants[0]).invoke(var2, (Complex)this.constants[1]);<br> }<br>}</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph">For <code class="lang-kotlin">LongRing</code>, <code class="lang-kotlin">IntRing</code>, and <code class="lang-kotlin">DoubleField</code> specialization is supported for better performance:</p><div class="sample-container"><pre><code class="block lang-java" theme="idea">import java.util.*;<br>import space.kscience.kmath.asm.internal.*;<br>import space.kscience.kmath.expressions.*;<br><br>public final class CompiledExpression_-386104628_0 implements DoubleExpression {<br> private final SymbolIndexer indexer;<br><br> public SymbolIndexer getIndexer() {<br> return this.indexer;<br> }<br><br> public double invoke(double[] arguments) {<br> double var2 = arguments[0];<br> return Math.pow(var2, 3.0D) - var2 + 3.0D;<br> }<br><br> public final Double invoke(Map&lt;Symbol, ? extends Double&gt; arguments) {<br> double var2 = ((Double)MapIntrinsics.getOrFail(arguments, "x")).doubleValue();<br> return Math.pow(var2, 3.0D) - var2 + 3.0D;<br> }<br>}</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph">Setting JVM system property <code class="lang-kotlin">space.kscience.kmath.ast.dump.generated.classes</code> to <code class="lang-kotlin">1</code> makes the translator dump class files to program's working directory, so they can be reviewed manually.</p><h4 class=""> Limitations</h4><ul><li><p class="paragraph">The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class loading overhead.</p></li><li><p class="paragraph">This API is not supported by non-dynamic JVM implementations like TeaVM or GraalVM Native Image because they may not support class loaders.</p></li></ul><h3 class=""> On JS</h3><p class="paragraph">A similar feature is also available on JS.</p><div class="sample-container"><pre><code class="block lang-kotlin" theme="idea">import space.kscience.kmath.expressions.Symbol.Companion.x<br>import space.kscience.kmath.expressions.*<br>import space.kscience.kmath.operations.*<br>import space.kscience.kmath.estree.*<br><br>MstField { x + 2 }.compileToExpression(DoubleField)</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph">The code above returns expression implemented with such a JS function:</p><div class="sample-container"><pre><code class="block lang-js" theme="idea">var executable = function (constants, arguments) {<br> return constants[1](constants[0](arguments, "x"), 2);<br>};</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph">JS also supports experimental expression optimization with <a href="https://webassembly.org/">WebAssembly</a> IR generation. Currently, only expressions inside <code class="lang-kotlin">DoubleField</code> and <code class="lang-kotlin">IntRing</code> are supported.</p><div class="sample-container"><pre><code class="block lang-kotlin" theme="idea">import space.kscience.kmath.expressions.Symbol.Companion.x<br>import space.kscience.kmath.expressions.*<br>import space.kscience.kmath.operations.*<br>import space.kscience.kmath.wasm.*<br><br>MstField { x + 2 }.compileToExpression(DoubleField)</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><p class="paragraph">An example of emitted Wasm IR in the form of WAT:</p><div class="sample-container"><pre><code class="block lang-lisp" theme="idea">(func \$executable (param \$0 f64) (result f64)<br> (f64.add<br> (local.get \$0)<br> (f64.const 2)<br> )<br>)</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div><h4 class=""> Limitations</h4><ul><li><p class="paragraph">ESTree expression compilation uses <code class="lang-kotlin">eval</code> which can be unavailable in several environments.</p></li><li><p class="paragraph">WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/).</p></li></ul><h2 class=""> Rendering expressions</h2><p class="paragraph">kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax.</p><p class="paragraph">Example usage:</p><div class="sample-container"><pre><code class="block lang-kotlin" theme="idea">import space.kscience.kmath.ast.*<br>import space.kscience.kmath.ast.rendering.*<br>import space.kscience.kmath.misc.*</code></pre><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div></div> </div>
</div>
<h2 class="">Packages</h2>
<div class="table"><a data-name="1930886389%2FPackages%2F1542328537" anchor-label="space.kscience.kmath.asm" id="1930886389%2FPackages%2F1542328537" data-filterable-set=":kmath-ast:dokkaHtmlPartial/jvmMain"></a>
<div class="table-row" data-filterable-current=":kmath-ast:dokkaHtmlPartial/jvmMain" data-filterable-set=":kmath-ast:dokkaHtmlPartial/jvmMain">
<div>
<div class="main-subrow ">
<div class=""><span class="inline-flex">
<div><a href="space.kscience.kmath.asm/index.html">space.kscience.kmath.asm</a></div>
<span class="anchor-wrapper"><span class="anchor-icon" pointing-to="1930886389%2FPackages%2F1542328537"></span>
<div class="copy-popup-wrapper "><span class="copy-popup-icon"></span><span>Link copied to clipboard</span></div>
</span></span></div>
<div class="pull-right">
<div class="platform-tags no-gutters">
<div class="platform-tag jvm-like">jvm</div>
</div>
</div>
</div>
<div></div>
</div>
</div>
<a data-name="72249916%2FPackages%2F353974653" anchor-label="space.kscience.kmath.ast" id="72249916%2FPackages%2F353974653" data-filterable-set=":kmath-ast:dokkaHtmlPartial/commonMain"></a>
<div class="table-row" data-filterable-current=":kmath-ast:dokkaHtmlPartial/commonMain" data-filterable-set=":kmath-ast:dokkaHtmlPartial/commonMain">
<div>
<div class="main-subrow ">
<div class=""><span class="inline-flex">
<div><a href="space.kscience.kmath.ast/index.html">space.kscience.kmath.ast</a></div>
<span class="anchor-wrapper"><span class="anchor-icon" pointing-to="72249916%2FPackages%2F353974653"></span>
<div class="copy-popup-wrapper "><span class="copy-popup-icon"></span><span>Link copied to clipboard</span></div>
</span></span></div>
<div class="pull-right">
<div class="platform-tags no-gutters">
<div class="platform-tag common-like">common</div>
</div>
</div>
</div>
<div></div>
</div>
</div>
<a data-name="-622937510%2FPackages%2F353974653" anchor-label="space.kscience.kmath.ast.rendering" id="-622937510%2FPackages%2F353974653" data-filterable-set=":kmath-ast:dokkaHtmlPartial/commonMain"></a>
<div class="table-row" data-filterable-current=":kmath-ast:dokkaHtmlPartial/commonMain" data-filterable-set=":kmath-ast:dokkaHtmlPartial/commonMain">
<div>
<div class="main-subrow ">
<div class=""><span class="inline-flex">
<div><a href="space.kscience.kmath.ast.rendering/index.html">space.kscience.kmath.ast.rendering</a></div>
<span class="anchor-wrapper"><span class="anchor-icon" pointing-to="-622937510%2FPackages%2F353974653"></span>
<div class="copy-popup-wrapper "><span class="copy-popup-icon"></span><span>Link copied to clipboard</span></div>
</span></span></div>
<div class="pull-right">
<div class="platform-tags no-gutters">
<div class="platform-tag common-like">common</div>
</div>
</div>
</div>
<div></div>
</div>
</div>
<a data-name="-2000073002%2FPackages%2F-359754593" anchor-label="space.kscience.kmath.estree" id="-2000073002%2FPackages%2F-359754593" data-filterable-set=":kmath-ast:dokkaHtmlPartial/jsMain"></a>
<div class="table-row" data-filterable-current=":kmath-ast:dokkaHtmlPartial/jsMain" data-filterable-set=":kmath-ast:dokkaHtmlPartial/jsMain">
<div>
<div class="main-subrow ">
<div class=""><span class="inline-flex">
<div><a href="space.kscience.kmath.estree/index.html">space.kscience.kmath.estree</a></div>
<span class="anchor-wrapper"><span class="anchor-icon" pointing-to="-2000073002%2FPackages%2F-359754593"></span>
<div class="copy-popup-wrapper "><span class="copy-popup-icon"></span><span>Link copied to clipboard</span></div>
</span></span></div>
<div class="pull-right">
<div class="platform-tags no-gutters">
<div class="platform-tag js-like">js</div>
</div>
</div>
</div>
<div></div>
</div>
</div>
<a data-name="452572206%2FPackages%2F-359754593" anchor-label="space.kscience.kmath.wasm" id="452572206%2FPackages%2F-359754593" data-filterable-set=":kmath-ast:dokkaHtmlPartial/jsMain"></a>
<div class="table-row" data-filterable-current=":kmath-ast:dokkaHtmlPartial/jsMain" data-filterable-set=":kmath-ast:dokkaHtmlPartial/jsMain">
<div>
<div class="main-subrow ">
<div class=""><span class="inline-flex">
<div><a href="space.kscience.kmath.wasm/index.html">space.kscience.kmath.wasm</a></div>
<span class="anchor-wrapper"><span class="anchor-icon" pointing-to="452572206%2FPackages%2F-359754593"></span>
<div class="copy-popup-wrapper "><span class="copy-popup-icon"></span><span>Link copied to clipboard</span></div>
</span></span></div>
<div class="pull-right">
<div class="platform-tags no-gutters">
<div class="platform-tag js-like">js</div>
</div>
</div>
</div>
<div></div>
</div>
</div>
</div>
</div>
<div class="footer"><span class="go-to-top-icon"><a href="#content" id="go-to-top-link"></a></span><span>© 2022 Copyright</span><span class="pull-right"><span>Generated by </span><a href="https://github.com/Kotlin/dokka"><span>dokka</span><span class="padded-icon"></span></a></span></div>
</div>
</div>
</body></html>