Variable Substitution
Giac.jl provides a substitute function with a Symbolics.jl-compatible interface for variable substitution in symbolic expressions.
Basic Usage
Single Variable Substitution
using Giac
# Create symbolic variables
@giac_var x y
# Create an expression
expr = x^2 + 2*x + 1
# Substitute x = 3
result = substitute(expr, Dict(x => 3))
# Returns: 16 (which is 9 + 6 + 1)
# Substitute with symbolic value
result = substitute(expr, Dict(x => y))
# Returns: y^2 + 2*y + 1Pair Syntax (Shorthand)
You can also pass pairs directly as positional arguments instead of building a Dict. Any number of pairs is accepted, and they are applied simultaneously — the same contract as the dict form. This matches the call shape used by Symbolics.substitute.
@giac_var x y
substitute(x + 1, x => 5) # 6 (single pair)
substitute(x*y, x => 1, y => 2) # 2 (multi-pair varargs)
substitute(x + 2*y, x => y, y => x) # y + 2*x (simultaneous swap)
substitute(x + 1) # x + 1 (zero pairs: no-op)Call Syntax
A GiacExpr can also be called with pair arguments — equivalent to substitute(expr, pairs...), inheriting its simultaneous semantics:
@giac_var a b c d t
expr = a*invoke_cmd(:sin, b*t + c) + d
expr(a => 15, b => 10, c => 5, d => 0) # 15*sin(10*t+5)The existing function-evaluation call shape (u(0), f(x)) is preserved; the substitution overload dispatches only when every argument is a Pair{<:GiacExpr}.
Multiple Variable Substitution
Substitute multiple variables simultaneously:
@giac_var x y z
expr = x*y + y*z + x*z
# Substitute multiple variables at once
result = substitute(expr, Dict(x => 1, y => 2, z => 3))
# Returns: 11 (which is 2 + 6 + 3)Variable Swapping
The substitution is performed simultaneously, making variable swapping work correctly:
@giac_var a b
expr = a^2 + b
# Simultaneous substitution correctly swaps variables
result = substitute(expr, Dict(a => b, b => a))
# Returns: b^2 + aWith Giac Functions
The substitute function works with any Giac-supported functions:
@giac_var θ
expr = invoke_cmd(:sin, θ) + invoke_cmd(:cos, θ)
# Substitute θ = π/4
using Giac.Commands: simplify
result = substitute(expr, Dict(θ => giac_eval("pi/4"))) |> simplify
# Returns: sqrt(2)Symbolic-to-Symbolic Substitution
Replace variables with complex expressions:
@giac_var x y
# x^2 with x = y + 1
result = substitute(x^2, Dict(x => y + 1))
# Returns: (y + 1)^2Chained Substitution
Apply multiple substitutions in sequence:
@giac_var x y z
expr = x + y + z
step1 = substitute(expr, x => 1)
step2 = substitute(step1, y => 2)
final = substitute(step2, z => 3)
# Returns: 6Comparison with Symbolics.jl
The API is designed to match Symbolics.jl's substitute function:
# Symbolics.jl style (works in Giac.jl)
substitute(expr, Dict(x => 2, y => 3))
# Single variable shorthand
substitute(expr, x => value)Edge Cases
@giac_var x y
# Empty Dict returns original expression
substitute(x + 1, Dict{GiacExpr, Int}()) # Returns: x + 1
# Missing variable is ignored
substitute(x + 1, Dict(y => 5)) # Returns: x + 1 (y not in expr)Matrix Substitution
The substitute function also works element-wise on GiacMatrix:
Single Variable in Matrix
@giac_var x
M = GiacMatrix([x x+1; 2*x x^2])
# Substitute x = 3 in all elements
result = substitute(M, x => 3)
# Returns: [[3, 4], [6, 9]]Multiple Variables in Matrix
@giac_var x y
M = GiacMatrix([x+y x*y; x-y x/y])
# Substitute x = 6, y = 2 in all elements
result = substitute(M, Dict(x => 6, y => 2))
# Returns: [[8, 12], [4, 3]]Partial Substitution
@giac_var x y
M = GiacMatrix([x y; x+y x*y])
# Only substitute x, leave y symbolic
result = substitute(M, Dict(x => 2))
# Returns: [[2, y], [2+y, 2*y]]Symbolic Substitution in Matrix
@giac_var x y
M = GiacMatrix([x^2 x; 1 x+1])
# Replace x with y+1
result = substitute(M, Dict(x => y + 1))
# Returns: [[(y+1)^2, y+1], [1, y+2]]Performance
substitute(expr, dict) calls the underlying CxxWrap binding giac_subst directly with structured Gen vector arguments built via make_vect, instead of formatting a subst(expr, [vars], [vals]) command string and re-parsing it. This avoids the GIAC parser on every call and preserves the precision of floating-point replacement values exactly. On a representative non-trivial expression (expr = sum(x^k + k*y for k in 1:50), Dict(x => 2, y => 3), 1000 calls), this is roughly 1.5–2× faster than the prior string-round-trip implementation; the exact factor is machine-dependent.
API Reference
Giac.substitute — Function
substitute(expr::GiacExpr, dict::AbstractDict{<:GiacExpr}) -> GiacExprSubstitute variables in a symbolic expression according to a dictionary mapping.
Performs simultaneous substitution of all variables in dict. The original expression is not modified.
Arguments
expr::GiacExpr: The expression to transformdict::AbstractDict: Mapping from variables (GiacExpr) to replacement values
Returns
GiacExpr: New expression with substitutions applied
Examples
julia> @giac_var x y;
julia> expr = x^2 + y;
julia> string(substitute(expr, Dict(x => 2)))
"4+y"
julia> string(substitute(expr, Dict(x => 2, y => 3)))
"7"See also
@giac_var: Create symbolic variables
substitute(expr::GiacExpr, pairs::Pair{<:GiacExpr}...) -> GiacExprSubstitute variables using one or more pair arguments, aligned with Symbolics.substitute.
Equivalent to substitute(expr, Dict(pairs)). All pairs are applied simultaneously (the canonical swap substitute(expr, x => y, y => x) therefore swaps x and y rather than collapsing). Calling with zero pairs returns the input expression unchanged.
Examples
julia> @giac_var x y;
julia> substitute(x + 1, x => 5)
GiacExpr: 6
julia> substitute(x*y, x => 1, y => 2)
GiacExpr: 2
julia> substitute(x + 2*y, x => y, y => x)
GiacExpr: y+2*xSee also
substitute(::GiacExpr, ::AbstractDict): Dict-based form
substitute(m::GiacMatrix, dict::AbstractDict{<:GiacExpr}) -> GiacMatrixSubstitute variables in each element of a symbolic matrix.
Performs element-wise substitution, applying the same variable mappings to every element of the matrix. Returns a new matrix with the same dimensions.
Arguments
m::GiacMatrix: The matrix to transformdict::AbstractDict: Mapping from variables (GiacExpr) to replacement values
Returns
GiacMatrix: New matrix with substitutions applied element-wise
Examples
@giac_var x y
M = GiacMatrix([x+1 2*x; y x*y])
substitute(M, Dict(x => 2)) # Returns matrix with x=2 substituted
substitute(M, Dict(x => 2, y => 3)) # Returns fully numeric matrixSee also
substitute(::GiacExpr, ::AbstractDict): Scalar expression substitution
substitute(m::GiacMatrix, pairs::Pair{<:GiacExpr}...) -> GiacMatrixElement-wise variant of substitute(::GiacExpr, ::Pair{<:GiacExpr}...) for symbolic matrices.
Equivalent to substitute(m, Dict(pairs)). All pairs are applied simultaneously to every element. Calling with zero pairs returns a structural copy of the input matrix.
Examples
julia> @giac_var x;
julia> M = GiacMatrix([x 2*x; x+1 x^2]);
julia> result = substitute(M, x => 3);
julia> result[1, 1]
GiacExpr: 3
julia> result[2, 2]
GiacExpr: 9See also
substitute(::GiacMatrix, ::AbstractDict): Dict-based matrix form