All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
-
MCP server integration:
giac_mcp_server()exposes Giac's CAS engine to MCP-aware LLM clients (Claude Desktop, Claude Code, Cursor, …) through a new weak-dependency package extensionGiacMCPExtonModelContextProtocol.jl. The server advertises two tools —giac_eval(Giac/Xcas expression in → textual result out, withCallToolResult(isError=true, ...)for genuine Julia exceptions) andgiac_search(keyword in → matching command names out, with a prefix-then-substring fallback so LLM-style queries like"matrix"or"prime"surface relevant commands). The MCPinitializehandshake'sserverInfo.versiondefaults to the running Giac.jl version so clients always see the right number. Users who do not loadModelContextProtocol.jlare unaffected — no transitive dependency, no precompilation cost. Seedocs/src/extensions/mcp.mdfor the full setup guide. -
Example MCP prompts in the documentation:
docs/src/extensions/mcp.mdnow ships a curated "Example prompts" gallery — French and English direct-style prompts (factorise avec giac x²-1,with giac, factor x^4 - 1) plus natural-language, story-style prompts that exercise the LLM's judgement when routing togiac_eval(e.g., "between which two integers does the real root of x^3 + x - 1 = 0 lie?", "my password is the prime just after one billion — what is it?"). A separategiac_searchblock shows catalogue-discovery prompts ("which commands deal with matrices?"). -
Direct
Genfast path forinvoke_cmd/giac_cmd(spec 069): the generic command dispatcher now bypasses the GIAC parser when all arguments have a directGenrepresentation (GiacExpr,Int32, Int32-fittingInt64, finiteFloat64). The path resolves arguments through_get_gen_or_eval/Gen(Int32(x))/Gen(Float64(x))and routes toapply_func0/apply_func1/apply_func2/apply_func3(positional, zeroStdVectorallocation) for arity 0–3 andapply_funcNwith aStdVector{Gen}for arity ≥ 4. Geometric-mean speed-up across the standard workload mix is ≈ 1.5× with per-workload wins up to ≈ 2× on commands whose result is a long symbolic expression (factor,expand). The existing string-concatenation path is preserved as a fallback forRational,Complex,AbstractIrrational,AbstractVector,GiacMatrix,±Inf/NaN,Symbol,String,DerivativeCondition,DerivativePoint,Function,BigInt,Int128, and out-of-Int32-rangeInt64— all existing call shapes continue to work unchanged. Beyond the speed-up, the fast path structurally eliminates theGen → string → parse → Genround-trip class of bug that motivated_giac_subst_vec_tier1(spec 065). SetGIAC_INVOKE_CMD_STRING_PATH=1to disable globally. -
CONTRIBUTORS.md: a top-level acknowledgements file listing the people who built, reviewed, and inspired this package — Giac authors (Bernard Parisse & Renée De Graeve), the originalGiac.jl(Harald Hofstaetter), Julia ecosystem reviewers (Viral B. Shah, Mosè Giordano, Max Horn), code contributors (John Verzani), feature/bug-report contributors (Thibault Duretz), and methodology inspiration (Sam Abbott). Linked from the README.
-
Doperator now accepts Unicode identifiers:D(ϕ)on a function variable defined as@giac_var 𝑧 ϕ(𝑧)previously failed withArgumentError: D() requires a function expression like u(t). The internal parser regex (_parse_function_expr) only matched ASCII letters, even though GIAC C++ and Julia both accept Unicode names. The regex now uses Unicode letter/number classes (\p{L},\p{N}), so Greek letters, mathematical italics, and other Unicode identifiers work withD(u),D(u, n), and chained forms. Reported by @tduretz. -
is_constantnow recognizes the GIACinfinityandundefatoms. Previously,is_constant(giac_eval("inf"))returnedfalsebecauseinfinitywas treated as a free identifier. After this fix, any expression built from these atoms — includinginf,+inf,-inf,+infinity,-infinity,unsigned_inf,1/0(which GIAC evaluates to+infinity), and0/0(which evaluates toundef) — is correctly classified as a constant.Giac.Constants.is_giac_constantpicks up these atoms via a name-based fallback, since GIAC's internal==reportsinfinity == infinityasfalse. As a follow-on fix,to_juliano longer infinitely recurses on these irreducible atoms (evalfis a no-op on them); it returns theGiacExprunchanged, matching the prior public behavior. Closes #19.Note: names like
nan,NaN,unsigned_infinity, andundefinedare not GIAC atoms — GIAC parses them as ordinary free identifiers (e.g.nan + 1yieldsnan+1exactly likexyz + 1yieldsxyz+1), so they remain non-constant.
-
build_functionSymbolics backend (Tier 3): a newbackend::Symbolkeyword onbuild_functionselects the evaluation engine. The defaultbackend = :giacis unchanged from v0.13. The newbackend = :symbolics(requiresusing Symbolics) round-trips the expression throughto_symbolicsand compiles it viaSymbolics.build_function, returning a native Julia callable that is autodiff-friendly (ForwardDiff, SciML solvers) and typically at least an order of magnitude faster in hot loops. Documented indocs/src/julia_functions.md, with a comparison table and a runtime benchmark.Error paths:
backend = :symbolicswithoutusing Symbolics, free symbols not bound byvars, GIAC heads with noto_symbolicstranslation, and bad backend symbols all surface as actionableArgumentErrors atbuild_functiontime. Closes #17 Tier 3.Naming caveat:
Symbolicsalso exportsbuild_function; with bothusing Giacandusing Symbolicsin scope, qualify asGiac.build_function(...)(this is the standard Julia convention for name conflicts and is documented in the docstring and docs page). (067-build-function-tier3)
build_function: convert aGiacExprinto a native Julia callable with one named call.f = build_function(expr, x, y)returns a closure satisfyingf(a, b) == to_julia(substitute(expr, x => a, y => b)), suitable as a drop-in argument toPlots.plot,Plots.surface, broadcasting (f.(xs)), and matrix comprehensions. The wrapper is intentionally thin — it composes the existingsubstitute+to_juliachain — and the underlying primitives remain available for cases that need a custom step in between. Documented indocs/src/julia_functions.md, with a comparison table toSymbolics.build_functionand SymPy'slambdify, and showcased in the existingexamples/04_plotting.jlPluto notebook. Closes #17. (066-build-function)
- Varargs
substitute:substitute(expr, x => 1, y => 2)and the matchingGiacMatrixform now accept any number ofPairarguments, aligned withSymbolics.substitute. Equivalent to the dict formsubstitute(expr, Dict(pairs)); all pairs are applied simultaneously. Calling with zero pairs returns the input unchanged. (065-substitute-tier1) - Call-syntax substitution: a
GiacExprcalled with pair arguments now performs substitution.expr(a => 15, b => 10, c => 5, d => 0)is equivalent tosubstitute(expr, a => 15, b => 10, c => 5, d => 0)and inherits its simultaneous semantics. The existing function-evaluation call shape (u(0),f(x)) is unchanged because the new method dispatches only onPair{<:GiacExpr}.... Idea contributed by @jverzani in PR #11. (065-substitute-tier1) - Julia
Functionarguments accepted by GIAC commands:_arg_to_giac_stringnow serializes aFunctionvalue asstring(nameof(arg)), so callers can pass a Julia function directly where the GIAC command expects a function name — e.g.combine(log(x) + 2*log(x), log)instead ofcombine(..., "log"). As a side effect, the same fallback also letssubstituteaccept aFunctionvalue (substitute(f, f => log)yieldslog). Contributed by @jverzani in PR #6. - Additional math operations on
GiacExpr— degree-based and pi-multiple trig variants (sind,cosd,sinpi,cospi,asind,acosd,atand,secd,cscd,cotd), paired trig (sincos,sincosd,sincospi— return a 2-tuple ofGiacExpr), angle conversion (deg2rad,rad2deg), exponential / logarithm extensions (exp2,exp10,log1p, two-argumentlog(b, x)for any base),adjoint(so postfix'works onGiacExpr), andzero/one(instance and::Type{GiacExpr}forms). Contributed by @jverzani in PR #9. GiacMatrixiteration and linear indexing:length(M)returnsrows * cols;for e in Mandcollect(M)walk the entries in column-major order (matching Julia'sMatrixconvention);M[i]andM[CartesianIndex(i, j)]provide linear and Cartesian indexing; andLinearIndices(M)/CartesianIndices(M)are available for converting between forms. Contributed by @jverzani in PR #10.- Introspection helpers:
is_constant,unwrap_const,free_symbols,hasmatch,iscall,operation,arguments,maketerm,Constants.is_giac_constant, identity constructorGiacExpr(::GiacExpr). These let callers query whether an expression is closed-form constant, enumerate its free symbols, and walk it as a syntax tree. Contributed by @jverzani in PR #8. Resolves issue #3. - TermInterface.jl extension (
GiacTermInterfaceExt): whenTermInterfaceis loaded,GiacExprparticipates in theiscall/operation/arguments/maketerm/isexprprotocol used by Metatheory.jl, SymbolicUtils.jl, and other rewriters. Pure weak-dep — no cost to users who don't loadTermInterface. Base.isfinite(::GiacExpr): returns a JuliaBool.isfinite(x)istruefor free identifiers, ordinary symbolic expressions, and finite numbers;falseforinf,-inf, and1/0(which GIAC normalizes to infinity). Implemented as!to_julia(isinf(expr))::Bool.- CommonSolve.jl integration:
Giac.Commands.solveis now the same generic function asCommonSolve.solve(Giac.Commands.solve === CommonSolve.solve), so Giac'ssolveparticipates in the broader Julia "solve" verb ecosystem alongsideDifferentialEquations.jl,NLsolve.jl,Symbolics.jl, etc. Dispatch is by argument type, so there is no conflict —solve(::GiacExpr, …)routes to GIAC,solve(::ODEProblem, …)routes to DifferentialEquations, and so on.CommonSolveis a tiny hard dependency (~50 LOC, compat0.2). Note thatCommonSolvealso exportsinitandsolve!as part of an iterative-solver protocol; Giac is a symbolic CAS (non-iterative) so onlysolveis extended —initandsolve!are left untouched and remain available for other packages to extend without conflict. Contributed by @jverzani in PR #7.
-
to_julia(::GiacExpr)now reduces free-variable-free expressions to numbers viaevalf. Previously,to_julia(substitute(sin(x), x => 2))returnedGiacExpr: sin(2)— the symbolic form was preserved even though the caller asked for a Julia value. Now it returns0.9092…(aFloat64). The layered design holds:evalf(expr)keeps you in Giac and returns aGiacExprwhose internal type isDOUBLE;to_julia(expr)bridges to a Julia number. Symbolic expressions with at least one free variable still pass through unchanged. This is a behavior change for users who relied onto_juliaof constant symbolic expressions returning aGiacExpr— useevalf(expr)instead if you want a numericGiacExpr. Resolves issue #3. -
^(::GiacExpr, ::Number)and^(::Number, ::GiacExpr)widened: powers onGiacExprpreviously accepted only anIntegerexponent; now anyNumberis accepted on either side viapromote. Existing^(::GiacExpr, ::Integer)calls continue to work unchanged. Contributed by @jverzani in PR #9. -
substitute(expr, dict)no longer round-trips through the GIAC parser. The dict-formsubstitutefor bothGiacExprandGiacMatrixnow calls the direct CxxWrap bindinggiac_substwith structuredGenvector arguments built viamake_vect. Simultaneous-substitution semantics (e.g.Dict(x => y, y => x)swapsxandy) and the public API are unchanged. On a representative non-trivial expression with two pairs, this is roughly 1.5–2× faster than the prior string-round-trip implementation (machine-dependent), and floating-point replacement values are preserved exactly. (065-substitute-tier1) -
substitute(expr, pair)single-pair method replaced by the new varargs method.substitute(expr, x => 1)continues to work without change; the dispatch path simply delegates to the new varargs definition. (065-substitute-tier1)
asind/acosd/atand: implementation wasasin(deg2rad(x))etc., which converted the input from degrees to radians instead of converting the angle output from radians to degrees (e.g.asind(1)returnedasin(π/180)instead of90). Corrected torad2deg(asin(x))(matches Julia Base). Note: GIAC keeps the result aspi/2 * 180/pi; callingsimplifyreduces it to the integer.sincos/sincosd/sincospi: return-type annotation was::GiacExprbut the body returned a 2-tuple, triggering aMethodErroron every call. Annotation changed to::Tuple{GiacExpr, GiacExpr}.
- Internal helper
_build_subst_command(no longer needed; the substitution path no longer constructs subst-command strings). Not part of the public API.
- Symbolic comparison and logical operators on
GiacExpr:<,>,<=,>=,&,|are now defined forGiacExpr, allowing symbolic conditions to be expressed directly (e.g.x < y,(x > 0) & (y < 1)). (#4)
to_giacwith Symbolics v7 literal numbers: handles symbolic literal numbers produced by Symbolics v7, fixing aTypeErrorwhen squaring or otherwise manipulating expressions converted from Symbolics. (#2, closes #1)
- JLL-based library loading:
GIAC_jllandlibgiac_julia_jllare now direct dependencies, providing the GIAC library and C++ wrapper automatically. No manual compilation or environment variables needed. - Windows support: Fixed POSIX
dup/dup2calls insearch_commands_by_descriptionto use Windows-compatible_dup/_dup2. - Symbolics 7 compatibility:
to_symbolicsnow returns consistentNumtype usingSymbolics.wrap()and pairwiseSymbolics.term()for multiplication, preserving symbolic forms likesqrt(2).
- BREAKING: Removed
is_stub_mode()from public API. Stub mode no longer exists — the library is always available via JLL packages. - BREAKING: Removed
TempApisubmodule. UseGiac.Commandsinstead for the same functions (diff,integrate,factor, etc.). - Removed all stub mode infrastructure (
_stub_modeflag, stub expressions, conditional branches in ~30 functions).
- BREAKING: Minimum Julia version raised from 1.10 to 1.11.
- Library initialization now throws
GiacErrorinstead of silently falling back to stub mode when the wrapper library is not found.
- HeldCmd LaTeX rendering: Specialized LaTeX renderers for
limit,sum,product, andsum_riemannheld commands. - HeldEquation tilde operator:
~operator support forHeldCmdwith LaTeX rendering. - GiacMatrix command support: GIAC commands now work with
GiacMatrixarguments. Base.numeratorandBase.denominatormethods forGiacExpr.
-
Symbolic Constants module (
Giac.Constants): Submodule providing symbolic mathematical constantspi,e, andiasGiacExprvalues:using Giac.Constants: pi, e, i expr = 2 * pi * x # stays symbolic
-
MathJSON.jl extension: Bidirectional conversion between
GiacExprand MathJSON expression trees viato_mathjsonandto_giac. -
Direct pointer conversion:
to_symbolicsandto_giacuse direct Gen pointer transfer instead of string serialization for better performance. -
Direct GMP binary transfer:
BigIntconversion uses direct memory transfer from GIAC's GMP integers, avoiding string parsing.
GiacSymbolicsExtusesGenTypesenum instead of magic numbers.- Factorized expressions preserved in
to_symbolicsconversion.
- GenTypes module:
Tenum for GIAC expression types with C++ alignment. - Pluto example notebooks: Basics and advanced usage notebooks with screenshots.
- Tier 2 N-ary dispatch for functions with >3 parameters.
- UnitRange indexing:
GiacMatrixand@giac_several_varssupportUnitRangeindices. - Z-transform functions:
ztransandinvztranswith documentation. - Laplace transform functions:
laplaceandilaplacewith documentation. - D operator: Derivative operator for ODE initial conditions.
- Callable GiacExpr:
f(x)syntax for function evaluation. - Extended
@giac_varmacro: Function syntax support.
- Domain documentation: Mathematics (algebra, calculus, linear algebra, ODEs, trigonometry) and physics (mechanics, electromagnetism) with test-verified examples.
- Vector input support: GIAC commands accept Julia vectors as arguments.
- Boolean conversion:
to_juliahandles GIAC boolean results.
to_juliaforsolveresults using CxxWrap bindings.- Correct
GIAC_STRNGtype constant.
- Tables.jl compatibility:
GiacMatrixand command help implement Tables.jl interface. - Julia help system integration:
?commandworks in the REPL. - Variable substitution:
substitutefunction with Symbolics.jl-compatible interface. - Output handling: Improved type conversion and introspection.
- Public
help()function (replaced by Julia help system integration).
-
Multiple dispatch for JULIA_CONFLICTS commands: GIAC commands that conflict with Julia (like
zeros,min,max,det,inv) now work withGiacExprarguments via multiple dispatch. -
Equation syntax with
~operator: Create symbolic equations using the tilde operator:@giac_var x eq = x^2 - 1 ~ 0 solve(eq, x)
- Suppressed misleading conflict warnings for non-keyword conflicts.
- BREAKING: Removed
giac_prefixed functions in favor ofGiac.Commandsequivalents.
Giac.TempApidelegated toinvoke_cmdinstead of removedgiac_*functions.
- BREAKING: Renamed
@giac_several_varto@giac_several_vars(plural form).
- Core symbolic expression type
GiacExpr - Expression evaluation with
giac_eval - Calculus operations:
giac_diff,giac_integrate,giac_limit,giac_series - Algebraic operations:
giac_factor,giac_expand,giac_simplify,giac_solve,giac_gcd - Symbolic variable macros:
@giac_var,@giac_several_vars - Matrix type
GiacMatrixwithdet,inv,tr,transpose - Command discovery:
list_commands,search_commands,suggest_commands - Commands submodule with ~2000 GIAC commands
- Performance tier system (Tier 1/2/3)
- Thread-safe evaluation with
GiacContext