Giac.jl

Bringing Giac computer algebra to Julia with interactive notebooks
Presentation: s-celles.github.io/Giac.jl_juliacon2026 QR code for the published presentation

Sébastien Celles

2026-08-12

Introduction

Sébastien Celles

  • 🏫 PRAG (professeur agrégé) at Université de Poitiers (France) ie teaching only position
  • 🎓 No research / no PhD - not mathematician but physicist specialising in Electrical Engineering and computer sciences.
  • 🐍 Python enthusiast (and many other languages) → Julia convert

QR code for the GitHub profile

🔗 github.com/s-celles

📎 Presentation: https://s-celles.github.io/Giac.jl_juliacon2026/

Julia & open-source contributions

  • 📖 Technical reviewer of Julia for Data Science (Joshi, A., 2016, Packt Publishing, ISBN 9781785289699)
  • 📦 ToonFormat.jl — Token-Oriented Object Notation (registered)
  • 🔗 PackageURLs.jl — Package URL (PURL) library, ECMA-427 compatible (registered)
  • 📐 JSXGraph.jl — interactive geometry plots (registered)
  • 🌐 gRPCServer.jl — gRPC server for Julia (unregistered but in touch with an OSCP for testing)
  • 🌐 Nghttp2Wrapper.jl — nghttp2 wrapper for Julia (registered) …

Why CAS? A personal journey

Ongoing project: Symbolic electrical circuit simulator

A very basic RLC circuit schematics

Symbolic impedance: \(Z(s) = R + sL + \frac{1}{sC}\)

What do we need from a CAS?

  • 🔌 Kirchhoff’s laws → system of symbolic equations
  • ⚡ Transfer functions, impedances, Laplace transforms
  • 📐 Need: solving, simplification, partial fractions
  • 🧮 Modified nodal analysis (MNA) - Kirchhoff’s Current Law (KCL) at each node (except ground)

The gap in Julia’s symbolic ecosystem

Symbolics.jl doesn’t yet support features I need (or at least I haven’t found how to do them):

The solution: Giac

Leverage Giac’s mature CAS (20-30 years of development) via Giac.jl:

  • laplace, ilaplace — Laplace and inverse Laplace transforms
  • partfrac — partial fraction decomposition
  • solve — algebraic & systems of equations
  • desolve — ordinary differential equations
  • ✅ 2000+ commands available

What is Giac?

Giac is a mature, open-source (GPL licensed) C++ computer algebra system developed by Bernard Parisse at Université Grenoble Alpes.

Giac Powers…

  • 🖥️ Xcas - Desktop CAS application
  • 📐 GeoGebra - Dynamic mathematics software
  • 🔢 HP Prime - Professional calculator

Xcas logo

Giac capabilities

  • Symbolic algebra & simplification
  • Calculus (derivatives, integrals, limits)
  • Polynomial arithmetic
  • Gröbner bases
  • Linear algebra
  • Equation solving (algebraic & ODEs)
  • And much more…

Giac in one integration benchmark

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%
  • For integration in this test, Giac ranks 5th, ahead of Reduce, MuPAD, Maxima, and SymPy.
  • Open question for 2026: should we refresh and extend this benchmark from Julia with Symbolics.jl, Giac.jl, and SymPy.jl—measuring both the CAS engines and their Julia interfaces?

Source: Nasser M. Abbasi, Computer Algebra Independent Integration Tests — Summer 2024

Why Giac.jl?

Previous Julia interfaces to Giac exist:

  • By Harald Hofstaetter
  • By Bernard Parisse himself

But they have seen limited maintenance and don’t integrate well with:

  • Modern Julia ecosystem
  • Notebook environments
  • Math interchange formats

The Giac.jl ecosystem - Project overview

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.

Core types

Type Purpose
GiacExpr Symbolic expression wrapper (wraps C++ gen pointer)
GiacMatrix Matrix operations wrapper
GiacContext Execution context (thread-local)
# GiacExpr supports:
# - Arithmetic: +, -, *, /, ^
# - Equations: x^2 - 1 ~ 0 (~ operator)
# - Method syntax: expr.factor(), expr.diff(x)
# - Iteration: for elem in vector_expr

Giac.jl features

  • 2000+ Giac commands via invoke_cmd(:cmd, args...) or Giac.Commands
  • Expression Evaluation: Parse and evaluate mathematical expressions
  • Arithmetic: +, -, *, /, ^, unary negation, equality
  • Algebra: Factorization, expansion, simplification, solving, GCD
  • Calculus: Differentiation, integration, limits, series
  • Linear Algebra: Symbolic matrices, determinant, inverse, eigenvalues

Giac.jl features (cont.)

  • Laplace/Z-Transform: Signal processing with laplace, ztrans
  • Type Conversion: Results to Julia types (Int64, Float64, Rational, BigInt via GMP)
  • Symbolics.jl Integration: Bidirectional tree-based conversion (Symbolics 7)
  • Tables.jl: Export GiacMatrix to DataFrames, CSV
  • LaTeX Support: Automatic rendering in Pluto notebooks (incl. HeldCmd)
  • Constants Module: Symbolic pi, e, i via Giac.Constants

Giac.jl - basic usage

using Giac
using Giac.Commands: factor, expand

@giac_var a b x y

# Symbolic arithmetic
a + b       # a+b
x ^ 2       # x^2

# Expand
expand((a + b)^2)    # a^2+2*a*b+b^2

# Factor
factor(x^2 - 1)      # (x-1)*(x+1)

# Simplify
simplify((x^2 - 1)/(x - 1))   # x+1

Command Discovery and Help

Giac 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/

Differentiation

using Giac
using Giac.Commands: diff

@giac_var x y

diff(x^3, x)                # 3*x^2
diff(x^4, x, 2)             # 12*x^2 (second derivative)
diff(sin(x^2), x)           # 2*x*cos(x^2) (chain rule)

Partial derivatives

using Giac
using Giac.Commands: diff

@giac_var x y

diff(x^2 * y^3, x)          # 2*x*y^3
diff(x^2 * y^3, y)          # 3*x^2*y^2

Integration

using Giac
using Giac.Commands: integrate

@giac_var x

# Indefinite
integrate(x^2, x)              # x^3/3
integrate(x * exp(x), x)       # (x-1)*exp(x)  (by parts)

# Definite
integrate(sin(x), x, 0, pi)    # 2

# Improper
integrate(exp(-x), x, 0, Inf)  # 1

Limits

using Giac
using Giac.Commands: limit

@giac_var x

limit(sin(x)/x, x, 0)              # 1
limit((x^2+1)/(2*x^2-3), x, Inf)   # 1/2
limit((exp(x)-1)/x, x, 0)          # 1 (L'Hôpital)

Series

using Giac
using Giac.Commands: series

@giac_var x

series(exp(x), x, 0, 4)   # 1+x+x^2/2+x^3/6+x^4/24+O(x^5)
series(sin(x), x, 0, 5)   # x-x^3/6+x^5/120+O(x^6)

# Solve ODEs
desolve(diff(y, x) ~ -2*y, x, y)    # c_0*exp(-2*x)

Laplace transforms & partial fractions

Key features for signal processing and circuit analysis:

using Giac
using Giac.Commands: laplace, ilaplace, partfrac

@giac_var s t x

# Laplace transform
laplace(exp(-2*t)*sin(3*t), t, s)   # 3/(s^2+4*s+13)

# Inverse Laplace
ilaplace(1/(s^2 + 1), s, t)         # sin(t)

# Partial fraction decomposition
partfrac(1/(x^2 - 1), x)            # 1/(2*(x-1)) - 1/(2*(x+1))

Solving equations

Solving single equations

using Giac
using Giac.Commands: solve

@giac_var x y

# Polynomial equations
solve(x^2 - 4, x)              # [-2, 2]
solve(x^2 + 2*x + 1, x)        # [-1]
solve(x^3 - 1, x)              # All roots including complex

# Using ~ operator (Symbolics.jl convention)
eq = x^2 - 1 ~ 0
solve(eq, x)                   # [-1, 1]

Solving equations (cont.)

Systems of equations

using Giac
using Giac.Commands: solve


# Systems of equations
solve([x + y ~ 1, x - y ~ 0], [x, y])  # [[1/2, 1/2]]

Symbolic matrices — GiacMatrix

The MNA matrix from earlier is built this way — entries stay symbolic end-to-end:

using Giac
using LinearAlgebra: det, inv, transpose

@giac_var a b c d

B = GiacMatrix([[a, b], [c, d]])

det(B)        # a*d - b*c
inv(B)        # symbolic 2×2 inverse
transpose(B)  # [[a, c], [b, d]]

Symbolic matrices — GiacMatrix (more constructors)

Two more constructors:

GiacMatrix([1 2; 3 4])     # from a Julia matrix literal
GiacMatrix(:m, 3, 3)       # 3×3 symbolic — entries m11..m33

Renders as LaTeX in notebooks (Pluto, KaimonSlate…) . Tables.jl integration → export to DataFrames / CSV.

Type conversion

Scalars

using Giac

to_julia(giac_eval("true"))   # true::Bool
to_julia(giac_eval("42"))     # 42::Int64
to_julia(giac_eval("3/4"))    # 3//4::Rational{Int64}

Vectors & components

using Giac

# Vector conversion
g = giac_eval("[1, 2, 3]")
to_julia(g)                    # [1, 2, 3]::Vector{Int64}

# Fraction components
frac = giac_eval("3/4")
numer(frac)  # 3
denom(frac)  # 4

Command access patterns

Four ways to invoke 2000+ commands:

  1. String evaluation (prototyping)
  2. Universal gateway (conflict-free)
  3. Commands module (explicit import)
  4. Method syntax (fluent API… but is that a Julian way?)
using Giac

# 1. String evaluation
giac_eval("factor(x^2-1)")

# 2. Universal gateway
invoke_cmd(:factor, giac_eval("x^2-1"))

# 3. Commands module
using Giac.Commands: factor
factor(x^2 - 1)

# 4. Method syntax
(x^2 - 1).factor()

MCP server — two MCP tools

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.

MCP in action — register and factor a semiprime

 claude mcp add-json --scope user "giac-cas" '{
  "command": "julia",
  "args": ["--startup-file=no",
           "--project=/home/scelles/.julia/environments/mcp-giac",
           "-e", "using Giac, ModelContextProtocol; start!(Giac.giac_mcp_server())"]
}'
Added stdio MCP server giac-cas to user config
❯ Use the giac-cas MCP server to factor
  632459103267572196107100983820469021721602147490918660274601

● giac-cas → giac_eval(expr:
    "ifactor(632459103267572196107100983820469021721602147490918660274601)")
  → 650655447295098801102272374367 × 972033825117160941379425504503
✻ Cogitated for 7s

Giac.jl vs Symbolics.jl

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.

Where Giac also excels — integer factorisation

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 action

using Giac
using Giac.Commands: ifactor

n = giac_eval("632459103267572196107100983820469021721602147490918660274601")
ifactor(n)
# 650655447295098801102272374367*972033825117160941379425504503

A 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.

Giac.jl ↔︎ LibPARI.jl

PARI/GP is a specialist CAS for computational number theory:

  • integer factorisation
  • algebraic number theory
  • elliptic curves, modular forms, L-functions

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.

using Giac, LibPARI

# PARI → Giac
p = gp_eval("factor(2^64 - 1)")
g = to_giac(p)

# Giac → PARI
pari(g) == p                       # true
pari(giac_eval("x^2 + 1"))        # t_POL

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.

Giac.jl & Symbolics.jl: complementary

Use Symbolics.jl for:

  • SciML ecosystem integration
  • ModelingToolkit workflows
  • Native Julia performance
  • MIT-licensed projects

Use Giac.jl for:

  • “Advanced” symbolic integration
  • Complex equation solving
  • Mature CAS features (2000+ commands)
  • Gröbner bases, ODEs, series

Best approach: Use both thanks to to_symbolics and to_giac functions! Bidirectional conversion supported (and probably some others Julia packages too!).

MathField: visual math input for the web

MathField by Arno Gourdol — a web component for math editing (part of the MathLive project).

  • WYSIWYG math editor
  • Keyboard & handwriting input
  • Outputs MathJSON (not just LaTeX)

🔗 mathlive.io/mathfield

MathField Example

Why MathField matters for Julia

  • Natural input for reactives notebooks (Pluto, KaimonSlate…)
  • Machine-readable output (MathJSON) — not just a string
  • Bidirectional: can render results too

Pipeline: User types math visually → MathJSON → Giac.jl computes → LaTeX display

MathJSON.jl

Parse, manipulate, and serialize MathJSON expressions.

MathJSON is a lightweight JSON-based interchange format from the CortexJS project.

MathJSON:

["Add", 
  ["Power", "x", 2], 
  1
]

Mathematics: \[x^2 + 1\]

PlutoMathInput.jl

A WYSIWYG math editor widget for Pluto notebooks.

Features:

  • Embeds MathLive MathField
  • Visual math input (not raw LaTeX!)
  • Reactive with @bind
  • Returns MathJSON
@bind expr MathInput()

Type: \(\int x^2 \, dx\)

Get: ["Integrate", ["Power", "x", 2], "x"]

MathJSONComputeEngineBridge.jl

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.

Interactive math input

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)
# Reactive pipeline: MathJSON → Giac → simplify
parse(MathJSONFormat, formula) |> to_giac |> simplify   # → 1

The user types math visually → MathJSON binding updates → the Giac pipeline re-runs instantly.

Reactive differentiation in Pluto.jl

# 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 |> simplify

Each edit of the MathField re-fires the pipeline — evaluate handles D, Integrate, Matrix, …

📓 Notebook: MathJSONComputeEngineBridge.jl/notebooks/example.jl

KaimonSlate — MathField in the cell source

KaimonSlate.jl by Kahli Burke — a reactive Julia notebook where the expression is typed visually, inside the partfrac(...) call.

  • Virtual math keyboard
  • Results rendered as LaTeX
  • Named cells + timing + FRESH staleness → reactive re-runs

🔌 GiacSlate.jl — Giac integration for KaimonSlate

🔗 kahliburke.github.io/KaimonSlate.jl (404)

📦 git.kahliburke.com/kahliburke/KaimonSlate.jl

KaimonSlate + AI agent

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.

Where gaps remain

Areas where Giac.jl needs work compared to other CAS:

  • Tensor calculus — Limited compared to specialized packages
  • Assumptions system — Probably less flexible than Sympy
  • Plotting — Native plotting in giac but untested in Giac.jl. Converting GiacExpr to Julia function thanks to build_function is possible
  • Users feedback — Need more real-world use cases to identify pain points and prioritize features

Contributing

All 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

Acknowledgments

  • Bernard Parisse (@parisseb) & Renée De Graeve (Univ. Grenoble Alpes) - Giac/Xcas
  • Harald Hofstaetter (@HaraldHofstaetter) - Original Giac.jl implementation
  • Arno Gourdol (@arnog) - MathLive, MathJSON, CortexJS Compute Engine
  • Kahli Burke (@kahliburke) - KaimonSlate.jl reactive notebook & Kaimon.jl MCP server

Patient reviewers of the Yggdrasil PRs

  • Viral B. Shah (@ViralBShah) - Julia co-creator, Yggdrasil guidance
  • Mosè Giordano (@giordano) - BinaryBuilder reviewer
  • Max Horn (@fingolfin) - BinaryBuilder reviewer

s-celles/Giac.jl contributors

  • John Verzani (@jverzani) — early tester and major v0.12.0 contributor (introspection APIs, math operations, and GiacMatrix iteration/indexing)
  • Thibault Duretz (@tduretz — early tester and contributor of the build_function function feature idea (quite similar to lambdify in SymPy )

Full circle

Remember the motivation?

Symbolic electrical circuit simulator needing:

  • ✅ Laplace transforms → laplace, ilaplace
  • ✅ System solving → solve
  • ✅ Partial fractions → partfrac
  • ✅ Simplification → simplify

Giac.jl provides all of these!

CASSys.jl — coming next year?

Vision:

  • 🎓 Educational tool for Electrical Engineering students
  • 🔌 Symbolic Modified Nodal Analysis
  • 🔋 Symbolic voltage, current probes
  • ⚡ Symbolic transfer functions

Built on:

  • Symbolics.jl — native Julia symbolics
  • Giac.jl — advanced CAS (Laplace, partfrac) where Symbolics.jl falls short
  • ModelingToolkitStandardLibrary.jl / Electrical or DyadLang/ElectricalComponents — component library

Thank you!

Questions?

Giac.jl - Computer Algebra System for Julia

Developer Notes

Six-layer architecture

From user code down to the native C++ library:

  1. User Code — Scripts, Pluto notebooks, REPL sessions
  2. Giac.jl API — High-level Julia interface (@giac_var, Giac.Commands)
  3. Core TypesGiacExpr, GiacMatrix, GiacContext wrappers

Six-layer architecture

  1. FFI Layer — CxxWrap.jl bindings to C++ via PIMPL pattern
    • FFI (Foreign Function Interface): mechanism for calling C++ code from Julia
    • PIMPL (Pointer to IMPLementation): Julia only sees an opaque pointer, never Giac’s C++ internals — this isolates header conflicts between Giac and CxxWrap
  2. JLL Binarieslibgiac_julia_jll, pre-built via BinaryBuilder
  3. Giac C++GIAC_jll, the native CAS engine

Six-layer architecture

%%{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

libgiac-julia-wrapper

CxxWrap.jl bindings exposing Giac to Julia (v0.5.0, GPLv3)

  • PIMPL pattern (Pointer to IMPLementation): Gen and GiacContext expose only an opaque pointer — all C++ internals are hidden behind it
  • Firewall header: Giac and JLCXX headers conflict, so they are compiled in separate translation units — PIMPL makes this possible
  • Meson build system (migrated from CMake)
  • Cross-platform: Linux, macOS, Windows

3-tier function dispatch

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

libgiac-julia-wrapper types

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.

Development methodology and giving back to the LLM

Spec-Driven Development with AI assistance

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.

MCP server — Giac as a tool for LLMs

Weak-dependency extension GiacMCPExt exposes Giac to any MCP-aware client (Claude Desktop, Claude Code, Cursor) via ModelContextProtocol.jl.

using Giac, ModelContextProtocol
start!(giac_mcp_server())   # STDIO transport

Giac.jl and Symbolics.jl: a bridge for advanced symbolic computation

Symbolics today vs Giac via the bridge — headline trio

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.

Symbolics today vs Giac via the bridge — and more

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.

How the bridge works — two functions

using Giac, Symbolics   # GiacSymbolicsExt auto-loads

@variables x

# Symbolics → Giac
g = to_giac(x^2 + 2x + 1)

# Giac → Symbolics
s = to_symbolics(g)

Tree-traversal converters — not a string(expr) round-trip:

  • Int32-range integers → direct C++ constructor
  • BigInt → GMP __gmpz_export (binary, no string parsing)
  • π, , i preserved as Symbolics constants
  • Factored forms preserved — 2³·5³ is not collapsed to 1000

Source: ext/GiacSymbolicsExt.jl.

Bridge example (1/3) — polynomial factorization

Symbolics.factor delegates to Primes.factor and errors out on a polynomial:

using Symbolics, Giac
@variables x

Symbolics.factor(x^4 - 1)
# ERROR: MethodError: no method matching factor(::Num)

Through the bridge:

to_symbolics(Giac.Commands.factor(to_giac(x^4 - 1)))
# (x - 1)*(x + 1)*(x^2 + 1)

In flight: PR #1843 adds native Symbolics.factor(f, x) (AI-generated draft, unmerged).

Bridge example (2/3) — exact constants in transcendental solve

Symbolics.symbolic_solve evaluates π/3 as a Float64:

Tracked in #1842

julia> Symbolics.symbolic_solve(cos(x) ~ 1//2, x)
[ Info: var"##296" ϵ Ζ
1-element Vector{SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{SymReal}}:
 1.0471975511965976 + 6.283185307179586var"##296"

Through the bridge — π/3 stays exact:

Giac.Commands.solve(cos(to_giac(x)) ~ 1//2, to_giac(x))
# [-π/3, π/3]

Bridge example (3/3) — Diophantine over ℤ vs ℚ

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 ⏳.