Model API

The Model API provides a JuMP-inspired interface using SymbolicModel and macros for defining symbolic optimization problems.

Basic Usage

using SymbolicOptimization

model = SymbolicModel()

@variables model x y
@operators model [+, -, *, /] [sin, cos]
@data model X y_data
@objective model mse
@objective model complexity
@config model population=200 generations=100

optimize!(model)

println(expression_string(model))
println(objective_value(model))

Macros

@variables

Define the variable names for the search space:

@variables model x y z

@operators

Set binary and unary operators:

@operators model [+, -, *, /] [sin, cos, exp]

@constants

Configure the constant range:

@constants model (-5.0, 5.0)

@objective

Add optimization objectives:

@objective model mse
@objective model complexity

@constraint

Add constraints to the search:

@constraint model max_depth 6
@constraint model max_nodes 30

@seed

Provide seed expressions:

@seed model expr_tree

@data

Provide training data:

@data model X_matrix y_vector

@config

Set configuration options:

@config model population=200 generations=100 seed=42

@grammar

Define a full grammar directly:

@grammar model my_grammar

@problem

Composite macro that combines multiple definitions:

@problem model begin
    @variables x y
    @operators [+, -, *] [sin]
    @data X y
end

Programmatic API

For cases where macros are less convenient:

model = SymbolicModel()
set_variables!(model, [:x, :y])
set_operators!(model, binary=[+, -, *], unary=[sin])
set_constants!(model, (-5.0, 5.0))
set_data!(model, X, y)
set_config!(model, population=200)
add_constraint!(model, :max_depth, 6)
add_seed!(model, seed_tree)

optimize!(model)

Inspecting Results

expression_string(model)   # Best expression as string
expression_latex(model)    # Best expression as LaTeX
predict(model, X_new)      # Predictions on new data
objective_value(model)     # Objective values
history(model)             # Optimization history
raw_result(model)          # Full NSGAIIResult

Model API Reference

SymbolicOptimization.API.SymbolicModelType
SymbolicModel(; kwargs...)

Create a new symbolic optimization model.

A SymbolicModel is the central object for specifying and solving symbolic optimization problems. It collects all problem components (grammar, objectives, constraints, data, configuration) in one place, inspired by JuMP.jl's Model.

Quick Start

m = SymbolicModel()
@variables(m, x, y)
@operators(m, binary=[+, -, *, /])
@objective(m, Min, :mse)
@objective(m, Min, :complexity)
@data(m, X=my_X, y=my_y)
optimize!(m)
best(m)

Optional keyword arguments

  • seed::Int – random seed for reproducibility
  • verbose::Bool – print progress (default: true)
source
SymbolicOptimization.API.optimize!Function
optimize!(m::SymbolicModel) -> SymbolicModel

Run the symbolic optimization. Populates m with results accessible via best(m), pareto_front(m), etc.

m = SymbolicModel()
# ... set up model ...
optimize!(m)

# Access results
best(m)                    # best solution
pareto_front(m)            # all Pareto-optimal solutions
best(m, objective=2)       # best for 2nd objective
objective_value(m)         # objective values of the best
expression_string(m)       # string form of best expression
expression_latex(m)        # LaTeX form
source
SymbolicOptimization.API.set_operators!Function
set_operators!(m::SymbolicModel; binary=nothing, unary=nothing, ternary=nothing)

Set the operators available in the grammar.

set_operators!(m, binary=[+, -, *, /], unary=[sin, cos, exp])
source
SymbolicOptimization.API.set_constants!Function
set_constants!(m::SymbolicModel, lo::Real, hi::Real; probability=0.3)
set_constants!(m::SymbolicModel, ::Nothing)  # disable constants

Set the constant range and sampling probability, or disable constants.

set_constants!(m, -2.0, 2.0, probability=0.3)
set_constants!(m, nothing)  # no constants
source
SymbolicOptimization.API.set_data!Function
set_data!(m::SymbolicModel; kwargs...)

Set data/environment for the optimization.

For regression problems:

set_data!(m, X=my_X, y=my_y)

For policy problems (custom evaluators):

set_data!(m, trials=trial_data, labels=label_data, custom_param=42)
source
SymbolicOptimization.API.set_config!Function
set_config!(m::SymbolicModel; kwargs...)

Set optimization configuration.

set_config!(m,
    population = 500,
    generations = 150,
    max_depth = 8,
    max_nodes = 40,
    tournament_size = 5,
    crossover_prob = 0.7,
    mutation_prob = 0.3,
    parsimony_tolerance = 0.01,
    early_stop = 20,
    seed = 42,
    verbose = true
)
source
SymbolicOptimization.API.add_constraint!Function
add_constraint!(m::SymbolicModel, name::Symbol, test_fn::Function; description="")

Add a constraint. The test_fn has signature (tree, evaluate_fn) -> (satisfied::Bool, violation_score::Float64).

add_constraint!(m, :neutrality, (tree, eval_fn) -> begin
    # ... check constraint
    return (is_satisfied, violation_score)
end, description="c(H,E)=0 when P(H|E)=P(H)")
source
SymbolicOptimization.API.set_constraint_mode!Function
set_constraint_mode!(m::SymbolicModel, mode::Symbol; penalty_weight=1.0)

Set how constraints are enforced: :soft (penalty) or :hard (rejection).

set_constraint_mode!(m, :hard)
set_constraint_mode!(m, :soft, penalty_weight=2.0)
source
SymbolicOptimization.API.add_seed!Function
add_seed!(m::SymbolicModel, tree::AbstractNode)

Add a seed expression tree to the initial population.

Prefer the @seed macro for natural syntax:

@seed(m, pH_E - pH)

For programmatic use:

add_seed!(m, FunctionNode(:-, [Variable(:pH_E), Variable(:pH)]))
source
SymbolicOptimization.API.predictFunction
predict(m::SymbolicModel, X::AbstractMatrix; objective=1) -> Vector{Float64}

Evaluate the best expression on new data.

X_test = [1.0 2.0; 3.0 4.0]
preds = predict(m, X_test)
source
SymbolicOptimization.API.expr_to_treeFunction
expr_to_tree(expr, var_names::Set{Symbol}) -> AbstractNode

Convert a Julia expression AST into an expression tree.

Recognizes:

  • Symbols that match variable names → Variable nodes
  • Numeric literals → Constant nodes
  • Function calls → FunctionNode with the function name as symbol
  • Infix operations (+, -, *, /) → FunctionNode
  • Unary minus (-x) → FunctionNode(:*, [Constant(-1.0), x])
source