Rand Stats

CortexJS

zef:antononcube

Raku-CortexJS

Actions Status Actions Status Actions Status

Raku client for the MathLive Cortex-JS Compute Engine.


Installation

Preliminary setup (Node.js and Node packages)

CortexJS starts a Node.js backend process and requires the @cortex-js/compute-engine package to be available.

macOS (Homebrew):

brew install node
npm install @cortex-js/compute-engine

Linux (Debian/Ubuntu):

sudo apt update
sudo apt install -y nodejs npm
npm install @cortex-js/compute-engine

Windows (winget, PowerShell):

winget install OpenJS.NodeJS.LTS
npm install @cortex-js/compute-engine

Verify:

node --version
npm list @cortex-js/compute-engine

Raku package installation

Install this Raku package, "CortexJS", from Zef ecosystem:

zef install CortexJS

From GitHub:

zef install https://github.com/antononcube/Raku-CortexJS.git

How it works?

CortexJS::ComputeEngine is a Raku wrapper around a long-lived Node.js backend. When you call ComputeEngine.new, the wrapper:

  1. Resolves or loads the bridge JavaScript (ce-bridge.mjs) source.
  2. Starts a Node process (node ...) through Proc::Async.
  3. Initializes stream handlers for stdout (responses) and stderr (diagnostics).
  4. Sends an initial ping request to confirm the backend is ready.

During the session, each Raku method call (for example parse-latex, simplify, evaluate, expand, solve) is converted into a JSON request and written to the Node process stdin. The bridge executes the operation with @cortex-js/compute-engine and writes a JSON response back to stdout. The Raku side matches responses and returns the decoded result to your code.

When done, call .close (or let object destruction trigger cleanup) to stop the backend process.

flowchart TD
    A["Raku code: ComputeEngine.new()"] --> B["Resolve/load bridge JS source"]
    B --> C["Start Node backend process (Proc::Async)"]
    C --> D["Attach stdout/stderr handlers"]
    D --> E["Send ping"]
    E --> F{"Ping ok?"}
    F -- "No" --> G["Throw startup error"]
    F -- "Yes" --> H

    
    H{"Computations<br>finished?"} --> |No| I["Raku method call (parse/evaluate/simplify/...)"]
    I --> J["Serialize request as JSON line"]
    J --> K["Write request to Node stdin"]
    K --> L["Bridge executes CE operation"]
    L --> M["Write JSON response to stdout"]
    M --> N["Raku decodes and matches response"]
    N --> O["Return result to caller"]
    O --> H

    H --> |Yes|P["close() / DESTROY"]
    P --> Q["Close stdin + kill backend process"]
    
    subgraph RS["Computation Session"]
        H 
        I
        J
        K
        L
        M
        N
        O
    end

Basic usage

Make a new computation engine object and evaluate a LaTeX expression:

use CortexJS;
my $ce = ComputeEngine.new;

$ce.evaluate($ce.parse-latex('e^{i\\pi}'))
# -1

Expand expression:

$ce.to-latex($ce.expand($ce.parse-latex('(a + b)^2')));
# a^2+b^2+2ab

Simplify expression:

my $expr = $ce.parse-latex('3x^2 + 2x^2 + x + 5');
say "{$ce.to-latex($expr)} = {$ce.to-latex($ce.simplify($expr))}";
# 2x^2+3x^2+x+5 = 5x^2+x+5

Using assignment for repeated expression evaluation:

my $expr = $ce.parse-latex("3x^2+4x+2");

for (0, 0.1 ... 1) -> $x {
  $ce.assign('x', $x);
  say "f($x) = {$ce.evaluate($expr)}";
}
# f(0) = 2
# f(0.1) = 2.43
# f(0.2) = 2.92
# f(0.3) = 3.47
# f(0.4) = 4.08
# f(0.5) = 4.75
# f(0.6) = 5.48
# f(0.7) = 6.27
# f(0.8) = 7.12
# f(0.9) = 8.03
# f(1) = 9

Can be put in the last code block:

LEAVE $ce.close;
# (Any)

References

[ML1] MathLive.io, Compute Engine.