Bringing Giac computer algebra to Julia with interactive notebooks
Presentation: s-celles.github.io/Giac.jl_juliacon2026 
2026-08-12
Sébastien Celles

📎 Presentation: https://s-celles.github.io/Giac.jl_juliacon2026/
Ongoing project: Symbolic electrical circuit simulator
A very basic RLC circuit schematics
Symbolic impedance: \(Z(s) = R + sL + \frac{1}{sC}\)
Symbolics.jl doesn’t yet support features I need (or at least I haven’t found how to do them):
Leverage Giac’s mature CAS (20-30 years of development) via Giac.jl:
laplace, ilaplace — Laplace and inverse Laplace transformspartfrac — partial fraction decompositionsolve — algebraic & systems of equationsdesolve — ordinary differential equationsGiac is a mature, open-source (GPL licensed) C++ computer algebra system developed by Bernard Parisse at Université Grenoble Alpes.

Important: this is not an overall CAS ranking. Symbolic integration is only one capability among algebraic simplification, equation solving, transforms, linear algebra, and many others.
Independent integration benchmark (Summer 2024): 106,812 integrals, nine systems.
| Rank | CAS | Solved | Rank | CAS | Solved |
|---|---|---|---|---|---|
| 1 | Mathematica | 97.4% | 5 | Giac/Xcas | 57.5% |
| 2 | Rubi | 93.1% | 6 | Reduce | 54.3% |
| 3 | Maple | 83.8% | 7 | MuPAD | 52.8% |
| 4 | FriCAS | 77.2% | 8 | Maxima | 52.5% |
| 9 | SymPy | 42.2% |
Source: Nasser M. Abbasi, Computer Algebra Independent Integration Tests — Summer 2024
Previous Julia interfaces to Giac exist:
But they have seen limited maintenance and don’t integrate well with:
| Package | Repository | Description |
|---|---|---|
| Giac.jl | github.com/s-celles/Giac.jl | Julia interface to Giac |
| libgiac-julia-wrapper | github.com/s-celles/libgiac-julia-wrapper | C++ wrapper for Julia |
| giac | github.com/s-celles/giac | The native Giac CAS engine - B. Parisse C++ code but with Meson build |
| Yggdrasil | Yggdrasil / GIAC | BinaryBuilder recipe for Giac |
See developer notes at the end of this talk for more details on the architecture and build system.
| Type | Purpose |
|---|---|
| GiacExpr | Symbolic expression wrapper (wraps C++ gen pointer) |
| GiacMatrix | Matrix operations wrapper |
| GiacContext | Execution context (thread-local) |
invoke_cmd(:cmd, args...) or Giac.Commandslaplace, ztranspi, e, i via Giac.ConstantsGiac provides a vast library of mathematical commands — all accessible from Julia via Giac.Commands and discoverable via search_commands and search_commands_by_description.
# Search for commands by prefix
search_commands("sin") # ["sin", "sinc", "sinh", ...]
# Search with regex
search_commands(r"^a.*n$") # Commands starting with 'a' and ending with 'n'
# Search by description (find commands by what they do)
search_commands_by_description("polynomial") # Commands related to polynomials
# List available categories
list_categories() # [:trigonometry, :calculus, :algebra, ...]
# Get commands in a category
commands_in_category(:trigonometry) # ["sin", "cos", "tan", "asin", ...]
commands_in_category(:algebra) # ["factor", "expand", "simplify", ...]See https://s-celles.github.io/Giac.jl/dev/command_discovery_help/
Key features for signal processing and circuit analysis:
The MNA matrix from earlier is built this way — entries stay symbolic end-to-end:
Two more constructors:
Renders as LaTeX in notebooks (Pluto, KaimonSlate…) . Tables.jl integration → export to DataFrames / CSV.
Four ways to invoke 2000+ commands:
Two MCP tools exposed:
giac_eval — evaluates any Xcas/Giac expression (~2200 commands reachable through one string). Julia errors returned as CallToolResult(isError=true) → MCP session stays alive.giac_search — keyword search over the catalog (matrix, laplace, …) with prefix-then-substring fallback.Philosophy: one eval tool, not 2200. The LLM already knows Xcas syntax — Giac is the execution engine, the LLM is the decider.
❯ Use the giac-cas MCP server to factor
632459103267572196107100983820469021721602147490918660274601
● giac-cas → giac_eval(expr:
"ifactor(632459103267572196107100983820469021721602147490918660274601)")
→ 650655447295098801102272374367 × 972033825117160941379425504503
✻ Cogitated for 7s
| Giac.jl | Symbolics.jl | |
|---|---|---|
| Backend | C++ (Giac, some decades of development) | Pure Julia |
| Ecosystem | Standalone CAS | SciML, ModelingToolkit |
| Performance | FFI overhead | Native Julia, code generation |
| License | GPL-3 | MIT |
See also: Groebner.jl — a pure Julia package for Gröbner bases.
Not a competition — different strengths for different use cases.
Also useful for Capture The Flag (CTF) challenges like Hackropole, FCSC, WeShall…:
Julia’s Primes.jl lacks advanced factorisation — JuliaMath/Primes.jl#159
ifactor in actionA 60-digit semiprime (product of two 30-digit primes) factorised in seconds.
Common format for RSA challenges in CTFs — very difficult with pure Julia packages.
PARI/GP is a specialist CAS for computational number theory:
LibPARI.jl is its independent, unofficial Julia wrapper.
GiacLibPARIExt is an optional extension: it auto-loads when both packages are used, with no hard dependency.
Bidirectional contract: values and variable names are preserved, but printed representations may change. Integers, rationals, reals, complex numbers, polynomials, vectors, and matrices can cross; unsupported types raise an explicit error.
Use Symbolics.jl for:
Use Giac.jl for:
Best approach: Use both thanks to to_symbolics and to_giac functions! Bidirectional conversion supported (and probably some others Julia packages too!).
MathField by Arno Gourdol — a web component for math editing (part of the MathLive project).
MathField Example
Pipeline: User types math visually → MathJSON → Giac.jl computes → LaTeX display
Parse, manipulate, and serialize MathJSON expressions.
MathJSON is a lightweight JSON-based interchange format from the CortexJS project.
A WYSIWYG math editor widget for Pluto notebooks.
Glue layer: MathJSON visual input → Giac.jl symbolic computation → LaTeX output
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#9558b2', 'primaryTextColor': '#fff', 'primaryBorderColor': '#7C3F9E', 'lineColor': '#389826', 'secondaryColor': '#4063d8', 'background': '#ffffff'}}}%%
flowchart LR
A["Visual Input<br/>(MathField)"] --> B["MathJSON"]
B --> C["Julia Symbolic<br/>(Giac.jl)"]
C --> D["Compute"]
D --> E["Result"]
E --> F["Display<br/>(LaTeX)"]
Warning
WIP — better Pluto.jl integration still needed.
In a Pluto notebook:
using PlutoMathInput
using MathJSON: MathJSONFormat, parse
using MathJSONComputeEngineBridge: evaluate
using Giac, Giac.Commands
# Visual math input — bound to a MathJSON default string
@bind formula MathInput(
default="[\"Add\",[\"Power\",[\"Sin\",\"x\"],2],[\"Power\",[\"Cos\",\"x\"],2]]",
format=:mathjson)The user types math visually → MathJSON binding updates → the Giac pipeline re-runs instantly.
# Cell 1: Setup
using PlutoMathInput
using MathJSON: MathJSONFormat, parse
using MathJSONComputeEngineBridge: evaluate
using Giac, Giac.Commands
# Cell 2: Input — pre-filled with D[x² + 3x − 1, x]
@bind formula MathInput(
default="[\"D\", [\"Add\",[\"Power\",\"x\",2],[\"Multiply\",3,\"x\"],-1], \"x\"]",
format=:mathjson, canonicalize=false)
# Cell 3: evaluate (resolves D / Integrate) → Giac → simplify (reactive!)
parse(MathJSONFormat, formula) |> evaluate |> to_giac |> simplifyEach edit of the MathField re-fires the pipeline — evaluate handles D, Integrate, Matrix, …
📓 Notebook: MathJSONComputeEngineBridge.jl/notebooks/example.jl

KaimonSlate.jl by Kahli Burke — a reactive Julia notebook where the expression is typed visually, inside the partfrac(...) call.
FRESH staleness → reactive re-runs🔌 GiacSlate.jl — Giac integration for KaimonSlate
Paired with Kaimon.jl, the notebook is an MCP surface: an LLM agent can read, run and edit cells.
A giac_intro notebook doubles as a live tour — algebra, calculus, Laplace, control systems, symbolic linear algebra — and as teaching material the agent can navigate.
Areas where Giac.jl needs work compared to other CAS:
GiacExpr to Julia function thanks to build_function is possibleAll packages are open source and welcome contributions!
| Package | Repository |
|---|---|
| giac | github.com/s-celles/giac (B. Parisse code but with Meson build) |
| libgiac-julia-wrapper | github.com/s-celles/libgiac-julia-wrapper |
| Giac.jl | github.com/s-celles/Giac.jl |
| MathJSON.jl | github.com/s-celles/MathJSON.jl |
| PlutoMathInput.jl | github.com/s-celles/PlutoMathInput.jl |
| MathJSONComputeEngineBridge.jl | github.com/s-celles/MathJSONComputeEngineBridge.jl |
| GiacSlate.jl | github.com/s-celles/GiacSlate.jl |
| CAScad (browser - no Julia) | github.com/s-celles/CAScad |
Remember the motivation?
Symbolic electrical circuit simulator needing:
laplace, ilaplacesolvepartfracsimplifyGiac.jl provides all of these!
Vision:
Built on:
Giac.jl - Computer Algebra System for Julia

From user code down to the native C++ library:
@giac_var, Giac.Commands)GiacExpr, GiacMatrix, GiacContext wrapperslibgiac_julia_jll, pre-built via BinaryBuilderGIAC_jll, the native CAS engine%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#9558b2', 'primaryTextColor': '#fff', 'primaryBorderColor': '#7C3F9E', 'lineColor': '#389826', 'secondaryColor': '#4063d8', 'background': '#ffffff'}}}%%
flowchart LR
User["👤 User Code<br/>(Scripts, Pluto)"]
API["📦 Giac.jl API<br/>(@giac_var, Commands)"]
Core["⚙️ Core Types<br/>(GiacExpr, GiacMatrix)"]
FFI["🔗 FFI Layer<br/>(CxxWrap.jl)"]
JLL["📦 JLL Binaries<br/>(libgiac_julia_jll)"]
Native["🏛️ Giac C++<br/>(GIAC_jll)"]
User --> API --> Core --> FFI --> JLL --> Native
CxxWrap.jl bindings exposing Giac to Julia (v0.5.0, GPLv3)
Gen and GiacContext expose only an opaque pointer — all C++ internals are hidden behind it| Tier | Strategy | Example |
|---|---|---|
| Tier 1 | Direct C++ calls (fastest) | sin, diff, solve, integrate |
| Tier 2 | N-ary generic dispatch by name | Functions with >3 parameters |
| Tier 3 | String evaluation (most flexible) | Most of the 2000+ commands |
Two opaque C++ types exposed to Julia:
| Type | Wraps | Role |
|---|---|---|
| Gen | giac::gen |
Universal expression (numbers, symbols, polynomials, …) |
| GiacContext | giac::context |
Evaluation context (thread-local, variables, settings) |
Both use PIMPL — Julia never sees Giac internals, only the opaque pointer.
This project (Giac.jl) and its ecosystem (both Julia and C++ code) was developed using Spec-Driven Development with AI assistance:
| Tool | Role |
|---|---|
| Claude Opus 4 | AI pair-programmer (Claude Code CLI) |
| GitHub SpecKit | Specification management and task tracking |
The loop closes: an AI agent helped build Giac.jl and now Giac.jl becomes in turn a tool for AI agents thanks to MCP.
Giac itself, the CAS, does not change: the ecosystem around it expands.
Weak-dependency extension GiacMCPExt exposes Giac to any MCP-aware client (Claude Desktop, Claude Code, Cursor) via ModelContextProtocol.jl.
As of Symbolics v7.19.0 (April 2026):
| Operation | Symbolics today | Giac via bridge |
|---|---|---|
factor(x^4 − 1) |
MethodError (delegates to Primes.factor) |
(x−1)(x+1)(x²+1) |
solve(cos(x) ~ 1//2) |
float 1.0471… (= Float64 π/3) |
exact ±π/3 |
isolve(21u + 28v = 7) |
rational line u = ⅓ − ⁴⁄₃·v |
integer family (−1+4k, 1−3k) |
Each gets a dedicated example slide next.
| Operation | Symbolics today | Giac via bridge |
|---|---|---|
simplify(tan(x) − sin(x)/cos(x)) |
unchanged | 0 |
partfrac(x/(x² − 1)) |
unchanged | ½/(x−1) + ½/(x+1) |
discriminant(ax²+bx+c, x) |
no method on Num |
b² − 4ac |
Pattern: to_giac → Giac.Commands.<op> → to_symbolics. Full set in examples/06_symbolics_bridge.jl.
Tree-traversal converters — not a string(expr) round-trip:
Int32-range integers → direct C++ constructorBigInt → GMP __gmpz_export (binary, no string parsing)π, ℯ, i preserved as Symbolics constants2³·5³ is not collapsed to 1000Source: ext/GiacSymbolicsExt.jl.
Symbolics.factor delegates to Primes.factor and errors out on a polynomial:
Through the bridge:
In flight: PR #1843 adds native Symbolics.factor(f, x) (AI-generated draft, unmerged).
Symbolics.symbolic_solve evaluates π/3 as a Float64:
Tracked in #1842
Through the bridge — π/3 stays exact:
Tradeoff: Symbolics gives the integer-indexed family π/3 + 2kπ but loses the exact constant; Giac gives principal values exactly. For downstream symbolic work (further simplify, integrate, render LaTeX) the exact form is what you want.
Symbolics is also missing half of the solutions (the -π/3 + 2kπ roots).
In flight: PR #1844 ⏳.

JuliaCon 2026 · Giac.jl · Computer Algebra System