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 + 1

Pair 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 + a

With 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)^2

Chained 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: 6

Comparison 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.substituteFunction
substitute(expr::GiacExpr, dict::AbstractDict{<:GiacExpr}) -> GiacExpr

Substitute 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 transform
  • dict::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

source
substitute(expr::GiacExpr, pairs::Pair{<:GiacExpr}...) -> GiacExpr

Substitute 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*x

See also

source
substitute(m::GiacMatrix, dict::AbstractDict{<:GiacExpr}) -> GiacMatrix

Substitute 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 transform
  • dict::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 matrix

See also

source
substitute(m::GiacMatrix, pairs::Pair{<:GiacExpr}...) -> GiacMatrix

Element-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: 9

See also

source