Symbolica: a full state of the art CAS in typst!

Hello! With the creator of the symbolica, a powerful CAS (Computer Algebra System) used in active research, we have worked to get a wasm plugin working.

This means that you can now use the full power of symbolica directly inside of your typst documents.

For example you can factor polynomials, or take derivatives, and then numerically evaluate,

#import "@preview/symbolica:0.1.0": *

#let x = symbol("x")
#let f = math($x^4 - 5 x^2 + 4$)

$
  f(x) &= #to-typst(f) \
       &= #to-typst(factor(f)) \
  f'(x) &= #to-typst(derivative(f, x))
$
#evaluate(f,values:((x,1.2),))

You can solve (non-linear) systems of equations,

#import "@preview/symbolica:0.1.0": *
#let solutions = solve(
  ($x^2 + y^2 - a$, $x - 2y - b$).map(math),
  ($x$, $y$).map(math),
  domain: "real",
)

#let (x, y) = solutions.branches.first().values.map(to-typst)
$ x = #x, quad y = #y $

And automatically integrate using RUBI

#import "@preview/symbolica:0.1.0": *

#let x = math($x$)
#let f = math($x / (x + 1)$)
#to-typst(integrate(f, x))

Since it is a full CAS, you can of course do standard things like replacement rules. I envision this as a really neat way to expose mathematical thinking. Usually when you write out a derivation, you write the state of the equation after each transformation.

You might say that you first distribute, then show the expanded expression. Then you isolate a variable, or re-express a sub-part of your expression by a definition.

All these transformations are replacement rules, and now you can write out the operation, not the states in between! This eliminates typos, makes repeating the calculation or derivation on a different input trivial, and also makes you reflect on what you’re actually doing!

Feedback, issues and comments are really appreciated!

24 Likes

I loove this and I’m super grateful that symbolica made a license exemption specifically for Typst! (I guess part of the reasoning is that the kind of high performance work that the commercial license is meant for won’t be done, but still – that’s extra work done to give something away for free!)

Thanks for building this, it’s one of the use cases I hoped I would see Typst cover at some point :slight_smile:

5 Likes

This looks awesome, congratulations!

One detail on how the package is imported in the readme: it might be worth considering to promote importing it under a different abbreviation than sym since this is already a module in the global typst namespace.

3 Likes

Yes someone also mentioned this on the discord! I’ll bundle this in with a bunch of improvements for the 0.2 release!

3 Likes

I am so glad to finally see this merged. I saw it early on Discord, but wasn’t sure just how long we’d have to wait to see such a performant CAS workable from within Typst itself. I’m already toying around with some polynomial operations.

I am curious about one asymmetry. After initiating an engine with the lines

#import "@preview/symbolica:0.1.0": init
#let engine = init(namespace: "symbolica")

one can start performing operations with individual keys in the engine dictionary. Many operations have direct analogues in the Parsely AST’s, but one notable operation supported in the Parsely grammar but not by Symbolica, unless i missed it, is the factorial operation.

Is this the intended behavior, where we create our own factorial operations?

Thanks! Factorials are already supported through the math parser: engine.math($5!$) gives 120. Internally, n! is translated to Symbolica’s built-in gamma(n + 1), so symbolic arguments work too, although they currently render using Gamma notation.

2 Likes

Oh, okay. I missed the parts with engine.math. Great to see!

Note that a custom engine is really only if you really want to control the namespace. Otherwise just #import "@preview/symbolica:0.1.0": * and then use math($5!$) without the module.

This is absolutely insane!!!