Repository files navigation

eggp - e-graph GP

eggp (e-graph genetic programming), follows the same structure as the traditional GP. The initial population is created using ramped half-and-half respecting a maximum size and maximum depth parameter and, for a number of generations, it will choose two parents using tournament selection, apply the subtree crossover with probability $pc$ followed by the subtree mutation with probability $pm$, when the offsprings replace the current population following a dominance criteria.

The key differences of eggp are:

- new solutions are inserted into the e-graph followed by one step of equality saturation to find and store some of the equivalent expressions of the new offspring.
- the current population is replaced by the set of individuals formed by: the Pareto front, the next front after excluding the first Pareto-front, and a selection of the last offspring at random until it reaches the desired population size.
- the subtree crossover and mutation are modified to try to generate an unvisited exp

This repository provides a CLI and a Python package for eggp with a scikit-learn compatible API for symbolic regression.

Instructions:

CLI

How to use

eggp - E-graph Genetic Programming for Symbolic Regression.
Usage: eggp (-d|--dataset INPUT-FILE) [-t|--test ARG] [-g|--generations GENS]
(-s|--maxSize ARG) [-k|--split ARG] [--print-pareto] [--trace] [--loss ARG] [--opt-iter ARG] [--opt-retries ARG] [--number-params ARG] [--nPop ARG] [--tournament-size ARG] [--pc ARG] [--pm ARG] [--non-terminals ARG] [--dump-to ARG] [--load-from ARG] [--moo]
An implementation of GP with modified crossover and mutation operators
designed to exploit equality saturation and e-graphs.
https://arxiv.org/abs/2501.17848
Available options:
-d,--dataset INPUT-FILE CSV dataset.
-t,--test ARG test data (default: "")
-g,--generations GENS Number of generations. (default: 100)
-s,--maxSize ARG max-size.
-k,--split ARG k-split ratio training-validation (default: 1)
--print-pareto print Pareto front instead of best found expression
--trace print all evaluated expressions.
--loss ARG loss function: MSE, Gaussian, Poisson, Bernoulli.
(default: MSE)
--opt-iter ARG number of iterations in parameter optimization.
(default: 30)
--opt-retries ARG number of retries of parameter fitting. (default: 1)
--number-params ARG maximum number of parameters in the model. If this
argument is absent, the number is bounded by the
maximum size of the expression and there will be no
repeated parameter. (default: -1)
--nPop ARG population size (Default: 100). (default: 100)
--tournament-size ARG tournament size. (default: 2)
--pc ARG probability of crossover. (default: 1.0)
--pm ARG probability of mutation. (default: 0.3)
--non-terminals ARG set of non-terminals to use in the search.
(default: "Add,Sub,Mul,Div,PowerAbs,Recip")
--dump-to ARG dump final e-graph to a file. (default: "")
--load-from ARG load initial e-graph from a file. (default: "")
--moo replace the current population with the pareto front
instead of replacing it with the generated children.
-h,--help Show this help text

The dataset file must contain a header with each features name, and the --dataset and --test arguments can be accompanied by arguments separated by ':' following the format:

filename.ext:start_row:end_row:target:features

where each ':' field is optional. The fields are:

  • start_row:end_row is the range of the training rows (default 0:nrows-1). every other row not included in this range will be used as validation
  • target is either the name of the (if the datafile has headers) or the index of the target variable
  • features is a comma separated list of names or indices to be used as input variables of the regression model.

Example of valid names: dataset.csv, mydata.tsv, dataset.csv:20:100, dataset.tsv:20:100:price:m2,rooms,neighborhood, dataset.csv:::5:0,1,2.

The format of the file will be determined by the extension (e.g., csv, tsv,...). To use multi-view, simply pass multiple filenames in double-quotes:

eggp --dataset "dataset1.csv dataset2.csv dataset3.csv" ...

Installation

To install eggp you'll need:

  • libz
  • libnlopt
  • libgmp
  • ghc-9.6.6
  • cabal or stack

Method 1: PIP

Simply run:

pip install eggp 

under your Python environment.

Method 2: cabal

After installing the dependencies (e.g., apt install libz libnlopt libgmp), install ghcup

For Linux, macOS, FreeBSD or WSL2:

curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh

For Windows, run the following in a PowerShell:

Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; try { & ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1-UseBasicParsing))) -Interactive -DisableCurl } catch { Write-Error $_ }

After the installation, run ghcup tui and install the latest stack or cabal together with ghc-9.6.6 (select the items and press i). To install srsimplify simply run:

cabal install

Python

Features

  • Scikit-learn compatible API with fit() and predict() methods
  • Genetic programming approach with e-graph representation
  • Support for multi-view symbolic regressionsee here
  • Customizable evolutionary parameters (population size, tournament selection, etc.)
  • Flexible function set selection
  • Various loss functions for different problem types
  • Parameter optimization with multiple restarts
  • Optional expression simplification through equality saturation
  • Ability to save and load e-graphs

Usage

Basic Example

fromeggpimportEGGPimportnumpyasnp# Create sample dataX=np.linspace(-10, 10, 100).reshape(-1, 1)
y=2*X.ravel() +3*np.sin(X.ravel()) +np.random.normal(0, 1, 100)
# Create and fit the modelmodel=EGGP(gen=100, nonterminals="add,sub,mul,div,sin,cos")
model.fit(X, y)
# Make predictionsy_pred=model.predict(X)
# Examine the resultsprint(model.results)

Multi-View Symbolic Regression

fromeggpimportEGGPimportnumpyasnp# Create multiple views of dataX1=np.linspace(-5, 5, 50).reshape(-1, 1)
y1=np.sin(X1.ravel()) +np.random.normal(0, 0.1, 50)
X2=np.linspace(0, 10, 100).reshape(-1, 1)
y2=np.sin(X2.ravel()) +np.random.normal(0, 0.2, 100)
# Create and fit multi-view modelmodel=EGGP(gen=150, nPop=200)
model.fit_mvsr([X1, X2], [y1, y2])
# Make predictions for each viewy_pred1=model.predict_mvsr(X1, view=0)
y_pred2=model.predict_mvsr(X2, view=1)

Integration with scikit-learn

fromsklearn.model_selectionimporttrain_test_splitfromsklearn.metricsimportmean_squared_errorfromeggpimportEGGP# Split dataX_train, X_test, y_train, y_test=train_test_split(X, y, test_size=0.2)
# Create and fit modelmodel=EGGP(gen=150, nPop=150, optIter=100)
model.fit(X_train, y_train)
# Evaluate on test sety_pred=model.predict(X_test)
mse=mean_squared_error(y_test, y_pred)
print(f"Test MSE: {mse}")

Parameters

ParameterTypeDefaultDescription
genint100Number of generations to run
nPopint100Population size
maxSizeint15Maximum allowed size for expressions (max 100)
nTournamentint3Tournament size for parent selection
pcfloat0.9Probability of performing crossover
pmfloat0.3Probability of performing mutation
nonterminalsstr"add,sub,mul,div"Comma-separated list of allowed functions
lossstr"MSE"Loss function: "MSE", "Gaussian", "Bernoulli", or "Poisson"
optIterint50Number of iterations for parameter optimization
optRepeatint2Number of restarts for parameter optimization
nParamsint-1Maximum number of parameters (-1 for unlimited)
splitint1Data splitting ratio for validation
simplifyboolFalseWhether to apply equality saturation to simplify expressions
dumpTostr""Filename to save the final e-graph
loadFromstr""Filename to load an e-graph to resume search

Available Functions

The following functions can be used in the nonterminals parameter:

  • Basic operations: add, sub, mul, div
  • Powers: power, powerabs, square, cube
  • Roots: sqrt, sqrtabs, cbrt
  • Trigonometric: sin, cos, tan, asin, acos, atan
  • Hyperbolic: sinh, cosh, tanh, asinh, acosh, atanh
  • Others: abs, log, logabs, exp, recip, aq (analytical quotient)

Methods

Core Methods

  • fit(X, y): Fits the symbolic regression model
  • predict(X): Generates predictions using the best model
  • score(X, y): Computes R² score of the best model

Multi-View Methods

  • fit_mvsr(Xs, ys): Fits a multi-view regression model
  • predict_mvsr(X, view): Generates predictions for a specific view
  • evaluate_best_model_view(X, view): Evaluates the best model on a specific view
  • evaluate_model_view(X, ix, view): Evaluates a specific model on a specific view

Utility Methods

  • evaluate_best_model(X): Evaluates the best model on the given data
  • evaluate_model(ix, X): Evaluates the model with index ix on the given data
  • get_model(idx): Returns a model function and its visual representation

Results

After fitting, the results attribute contains a pandas DataFrame with details about the discovered models, including:

  • Mathematical expressions
  • Model complexity
  • Parameter values
  • Error metrics
  • NumPy-compatible expressions

License

[LICENSE]

Citation

If you use EGGP in your research, please cite:

@inproceedings{eggp,
author = {de Franca, Fabricio Olivetti and Kronberger, Gabriel},
title = {Improving Genetic Programming for Symbolic Regression with Equality Graphs},
year = {2025},
isbn = {9798400714658},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
url = {https://doi.org/10.1145/3712256.3726383},
doi = {10.1145/3712256.3726383},
booktitle = {Proceedings of the Genetic and Evolutionary Computation Conference},
pages = {},
numpages = {9},
keywords = {Symbolic regression, Genetic programming, Equality saturation, Equality graphs},
location = {Malaga, Spain},
series = {GECCO '25},
archivePrefix = {arXiv},
eprint = {2501.17848},
primaryClass = {cs.LG}, }

Acknowledgments

The bindings were created following the amazing example written by wenkokke

Fabricio Olivetti de Franca is supported by Conselho Nacional de Desenvolvimento Cient'{i}fico e Tecnol'{o}gico (CNPq) grant 301596/2022-0.

Gabriel Kronberger is supported by the Austrian Federal Ministry for Climate Action, Environment, Energy, Mobility, Innovation and Technology, the Federal Ministry for Labour and Economy, and the regional government of Upper Austria within the COMET project ProMetHeus (904919) supported by the Austrian Research Promotion Agency (FFG).

About

Python wraper for eggp

Resources

Stars

16 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

eggp - e-graph GP

eggp (e-graph genetic programming), follows the same structure as the traditional GP. The initial population is created using ramped half-and-half respecting a maximum size and maximum depth parameter and, for a number of generations, it will choose two parents using tournament selection, apply the subtree crossover with probability $pc$ followed by the subtree mutation with probability $pm$, when the offsprings replace the current population following a dominance criteria.

The key differences of eggp are:

- new solutions are inserted into the e-graph followed by one step of equality saturation to find and store some of the equivalent expressions of the new offspring.
- the current population is replaced by the set of individuals formed by: the Pareto front, the next front after excluding the first Pareto-front, and a selection of the last offspring at random until it reaches the desired population size.
- the subtree crossover and mutation are modified to try to generate an unvisited exp

This repository provides a CLI and a Python package for eggp with a scikit-learn compatible API for symbolic regression.

Instructions:

CLI

How to use

eggp - E-graph Genetic Programming for Symbolic Regression.
Usage: eggp (-d|--dataset INPUT-FILE) [-t|--test ARG] [-g|--generations GENS]
(-s|--maxSize ARG) [-k|--split ARG] [--print-pareto] [--trace] [--loss ARG] [--opt-iter ARG] [--opt-retries ARG] [--number-params ARG] [--nPop ARG] [--tournament-size ARG] [--pc ARG] [--pm ARG] [--non-terminals ARG] [--dump-to ARG] [--load-from ARG] [--moo]
An implementation of GP with modified crossover and mutation operators
designed to exploit equality saturation and e-graphs.
https://arxiv.org/abs/2501.17848
Available options:
-d,--dataset INPUT-FILE CSV dataset.
-t,--test ARG test data (default: "")
-g,--generations GENS Number of generations. (default: 100)
-s,--maxSize ARG max-size.
-k,--split ARG k-split ratio training-validation (default: 1)
--print-pareto print Pareto front instead of best found expression
--trace print all evaluated expressions.
--loss ARG loss function: MSE, Gaussian, Poisson, Bernoulli.
(default: MSE)
--opt-iter ARG number of iterations in parameter optimization.
(default: 30)
--opt-retries ARG number of retries of parameter fitting. (default: 1)
--number-params ARG maximum number of parameters in the model. If this
argument is absent, the number is bounded by the
maximum size of the expression and there will be no
repeated parameter. (default: -1)
--nPop ARG population size (Default: 100). (default: 100)
--tournament-size ARG tournament size. (default: 2)
--pc ARG probability of crossover. (default: 1.0)
--pm ARG probability of mutation. (default: 0.3)
--non-terminals ARG set of non-terminals to use in the search.
(default: "Add,Sub,Mul,Div,PowerAbs,Recip")
--dump-to ARG dump final e-graph to a file. (default: "")
--load-from ARG load initial e-graph from a file. (default: "")
--moo replace the current population with the pareto front
instead of replacing it with the generated children.
-h,--help Show this help text

The dataset file must contain a header with each features name, and the --dataset and --test arguments can be accompanied by arguments separated by ':' following the format:

filename.ext:start_row:end_row:target:features

where each ':' field is optional. The fields are:

  • start_row:end_row is the range of the training rows (default 0:nrows-1). every other row not included in this range will be used as validation
  • target is either the name of the (if the datafile has headers) or the index of the target variable
  • features is a comma separated list of names or indices to be used as input variables of the regression model.

Example of valid names: dataset.csv, mydata.tsv, dataset.csv:20:100, dataset.tsv:20:100:price:m2,rooms,neighborhood, dataset.csv:::5:0,1,2.

The format of the file will be determined by the extension (e.g., csv, tsv,...). To use multi-view, simply pass multiple filenames in double-quotes:

eggp --dataset "dataset1.csv dataset2.csv dataset3.csv" ...

Installation

To install eggp you'll need:

  • libz
  • libnlopt
  • libgmp
  • ghc-9.6.6
  • cabal or stack

Method 1: PIP

Simply run:

pip install eggp 

under your Python environment.

Method 2: cabal

After installing the dependencies (e.g., apt install libz libnlopt libgmp), install ghcup

For Linux, macOS, FreeBSD or WSL2:

curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh

For Windows, run the following in a PowerShell:

Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; try { & ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1-UseBasicParsing))) -Interactive -DisableCurl } catch { Write-Error $_ }

After the installation, run ghcup tui and install the latest stack or cabal together with ghc-9.6.6 (select the items and press i). To install srsimplify simply run:

cabal install

Python

Features

  • Scikit-learn compatible API with fit() and predict() methods
  • Genetic programming approach with e-graph representation
  • Support for multi-view symbolic regressionsee here
  • Customizable evolutionary parameters (population size, tournament selection, etc.)
  • Flexible function set selection
  • Various loss functions for different problem types
  • Parameter optimization with multiple restarts
  • Optional expression simplification through equality saturation
  • Ability to save and load e-graphs

Usage

Basic Example

fromeggpimportEGGPimportnumpyasnp# Create sample dataX=np.linspace(-10, 10, 100).reshape(-1, 1)
y=2*X.ravel() +3*np.sin(X.ravel()) +np.random.normal(0, 1, 100)
# Create and fit the modelmodel=EGGP(gen=100, nonterminals="add,sub,mul,div,sin,cos")
model.fit(X, y)
# Make predictionsy_pred=model.predict(X)
# Examine the resultsprint(model.results)

Multi-View Symbolic Regression

fromeggpimportEGGPimportnumpyasnp# Create multiple views of dataX1=np.linspace(-5, 5, 50).reshape(-1, 1)
y1=np.sin(X1.ravel()) +np.random.normal(0, 0.1, 50)
X2=np.linspace(0, 10, 100).reshape(-1, 1)
y2=np.sin(X2.ravel()) +np.random.normal(0, 0.2, 100)
# Create and fit multi-view modelmodel=EGGP(gen=150, nPop=200)
model.fit_mvsr([X1, X2], [y1, y2])
# Make predictions for each viewy_pred1=model.predict_mvsr(X1, view=0)
y_pred2=model.predict_mvsr(X2, view=1)

Integration with scikit-learn

fromsklearn.model_selectionimporttrain_test_splitfromsklearn.metricsimportmean_squared_errorfromeggpimportEGGP# Split dataX_train, X_test, y_train, y_test=train_test_split(X, y, test_size=0.2)
# Create and fit modelmodel=EGGP(gen=150, nPop=150, optIter=100)
model.fit(X_train, y_train)
# Evaluate on test sety_pred=model.predict(X_test)
mse=mean_squared_error(y_test, y_pred)
print(f"Test MSE: {mse}")

Parameters

ParameterTypeDefaultDescription
genint100Number of generations to run
nPopint100Population size
maxSizeint15Maximum allowed size for expressions (max 100)
nTournamentint3Tournament size for parent selection
pcfloat0.9Probability of performing crossover
pmfloat0.3Probability of performing mutation
nonterminalsstr"add,sub,mul,div"Comma-separated list of allowed functions
lossstr"MSE"Loss function: "MSE", "Gaussian", "Bernoulli", or "Poisson"
optIterint50Number of iterations for parameter optimization
optRepeatint2Number of restarts for parameter optimization
nParamsint-1Maximum number of parameters (-1 for unlimited)
splitint1Data splitting ratio for validation
simplifyboolFalseWhether to apply equality saturation to simplify expressions
dumpTostr""Filename to save the final e-graph
loadFromstr""Filename to load an e-graph to resume search

Available Functions

The following functions can be used in the nonterminals parameter:

  • Basic operations: add, sub, mul, div
  • Powers: power, powerabs, square, cube
  • Roots: sqrt, sqrtabs, cbrt
  • Trigonometric: sin, cos, tan, asin, acos, atan
  • Hyperbolic: sinh, cosh, tanh, asinh, acosh, atanh
  • Others: abs, log, logabs, exp, recip, aq (analytical quotient)

Methods

Core Methods

  • fit(X, y): Fits the symbolic regression model
  • predict(X): Generates predictions using the best model
  • score(X, y): Computes R² score of the best model

Multi-View Methods

  • fit_mvsr(Xs, ys): Fits a multi-view regression model
  • predict_mvsr(X, view): Generates predictions for a specific view
  • evaluate_best_model_view(X, view): Evaluates the best model on a specific view
  • evaluate_model_view(X, ix, view): Evaluates a specific model on a specific view

Utility Methods

  • evaluate_best_model(X): Evaluates the best model on the given data
  • evaluate_model(ix, X): Evaluates the model with index ix on the given data
  • get_model(idx): Returns a model function and its visual representation

Results

After fitting, the results attribute contains a pandas DataFrame with details about the discovered models, including:

  • Mathematical expressions
  • Model complexity
  • Parameter values
  • Error metrics
  • NumPy-compatible expressions

License

[LICENSE]

Citation

If you use EGGP in your research, please cite:

@inproceedings{eggp,
author = {de Franca, Fabricio Olivetti and Kronberger, Gabriel},
title = {Improving Genetic Programming for Symbolic Regression with Equality Graphs},
year = {2025},
isbn = {9798400714658},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
url = {https://doi.org/10.1145/3712256.3726383},
doi = {10.1145/3712256.3726383},
booktitle = {Proceedings of the Genetic and Evolutionary Computation Conference},
pages = {},
numpages = {9},
keywords = {Symbolic regression, Genetic programming, Equality saturation, Equality graphs},
location = {Malaga, Spain},
series = {GECCO '25},
archivePrefix = {arXiv},
eprint = {2501.17848},
primaryClass = {cs.LG}, }

Acknowledgments

The bindings were created following the amazing example written by wenkokke

Fabricio Olivetti de Franca is supported by Conselho Nacional de Desenvolvimento Cient'{i}fico e Tecnol'{o}gico (CNPq) grant 301596/2022-0.

Gabriel Kronberger is supported by the Austrian Federal Ministry for Climate Action, Environment, Energy, Mobility, Innovation and Technology, the Federal Ministry for Labour and Economy, and the regional government of Upper Austria within the COMET project ProMetHeus (904919) supported by the Austrian Research Promotion Agency (FFG).

About

Python wraper for eggp

Resources

Stars

16 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

eggp - e-graph GP

eggp (e-graph genetic programming), follows the same structure as the traditional GP. The initial population is created using ramped half-and-half respecting a maximum size and maximum depth parameter and, for a number of generations, it will choose two parents using tournament selection, apply the subtree crossover with probability $pc$ followed by the subtree mutation with probability $pm$, when the offsprings replace the current population following a dominance criteria.

The key differences of eggp are:

- new solutions are inserted into the e-graph followed by one step of equality saturation to find and store some of the equivalent expressions of the new offspring.
- the current population is replaced by the set of individuals formed by: the Pareto front, the next front after excluding the first Pareto-front, and a selection of the last offspring at random until it reaches the desired population size.
- the subtree crossover and mutation are modified to try to generate an unvisited exp

This repository provides a CLI and a Python package for eggp with a scikit-learn compatible API for symbolic regression.

Instructions:

CLI

How to use

eggp - E-graph Genetic Programming for Symbolic Regression.
Usage: eggp (-d|--dataset INPUT-FILE) [-t|--test ARG] [-g|--generations GENS]
(-s|--maxSize ARG) [-k|--split ARG] [--print-pareto] [--trace] [--loss ARG] [--opt-iter ARG] [--opt-retries ARG] [--number-params ARG] [--nPop ARG] [--tournament-size ARG] [--pc ARG] [--pm ARG] [--non-terminals ARG] [--dump-to ARG] [--load-from ARG] [--moo]
An implementation of GP with modified crossover and mutation operators
designed to exploit equality saturation and e-graphs.
https://arxiv.org/abs/2501.17848
Available options:
-d,--dataset INPUT-FILE CSV dataset.
-t,--test ARG test data (default: "")
-g,--generations GENS Number of generations. (default: 100)
-s,--maxSize ARG max-size.
-k,--split ARG k-split ratio training-validation (default: 1)
--print-pareto print Pareto front instead of best found expression
--trace print all evaluated expressions.
--loss ARG loss function: MSE, Gaussian, Poisson, Bernoulli.
(default: MSE)
--opt-iter ARG number of iterations in parameter optimization.
(default: 30)
--opt-retries ARG number of retries of parameter fitting. (default: 1)
--number-params ARG maximum number of parameters in the model. If this
argument is absent, the number is bounded by the
maximum size of the expression and there will be no
repeated parameter. (default: -1)
--nPop ARG population size (Default: 100). (default: 100)
--tournament-size ARG tournament size. (default: 2)
--pc ARG probability of crossover. (default: 1.0)
--pm ARG probability of mutation. (default: 0.3)
--non-terminals ARG set of non-terminals to use in the search.
(default: "Add,Sub,Mul,Div,PowerAbs,Recip")
--dump-to ARG dump final e-graph to a file. (default: "")
--load-from ARG load initial e-graph from a file. (default: "")
--moo replace the current population with the pareto front
instead of replacing it with the generated children.
-h,--help Show this help text

The dataset file must contain a header with each features name, and the --dataset and --test arguments can be accompanied by arguments separated by ':' following the format:

filename.ext:start_row:end_row:target:features

where each ':' field is optional. The fields are:

  • start_row:end_row is the range of the training rows (default 0:nrows-1). every other row not included in this range will be used as validation
  • target is either the name of the (if the datafile has headers) or the index of the target variable
  • features is a comma separated list of names or indices to be used as input variables of the regression model.

Example of valid names: dataset.csv, mydata.tsv, dataset.csv:20:100, dataset.tsv:20:100:price:m2,rooms,neighborhood, dataset.csv:::5:0,1,2.

The format of the file will be determined by the extension (e.g., csv, tsv,...). To use multi-view, simply pass multiple filenames in double-quotes:

eggp --dataset "dataset1.csv dataset2.csv dataset3.csv" ...

Installation

To install eggp you'll need:

  • libz
  • libnlopt
  • libgmp
  • ghc-9.6.6
  • cabal or stack

Method 1: PIP

Simply run:

pip install eggp 

under your Python environment.

Method 2: cabal

After installing the dependencies (e.g., apt install libz libnlopt libgmp), install ghcup

For Linux, macOS, FreeBSD or WSL2:

curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh

For Windows, run the following in a PowerShell:

Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; try { & ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1-UseBasicParsing))) -Interactive -DisableCurl } catch { Write-Error $_ }

After the installation, run ghcup tui and install the latest stack or cabal together with ghc-9.6.6 (select the items and press i). To install srsimplify simply run:

cabal install

Python

Features

  • Scikit-learn compatible API with fit() and predict() methods
  • Genetic programming approach with e-graph representation
  • Support for multi-view symbolic regressionsee here
  • Customizable evolutionary parameters (population size, tournament selection, etc.)
  • Flexible function set selection
  • Various loss functions for different problem types
  • Parameter optimization with multiple restarts
  • Optional expression simplification through equality saturation
  • Ability to save and load e-graphs

Usage

Basic Example

fromeggpimportEGGPimportnumpyasnp# Create sample dataX=np.linspace(-10, 10, 100).reshape(-1, 1)
y=2*X.ravel() +3*np.sin(X.ravel()) +np.random.normal(0, 1, 100)
# Create and fit the modelmodel=EGGP(gen=100, nonterminals="add,sub,mul,div,sin,cos")
model.fit(X, y)
# Make predictionsy_pred=model.predict(X)
# Examine the resultsprint(model.results)

Multi-View Symbolic Regression

fromeggpimportEGGPimportnumpyasnp# Create multiple views of dataX1=np.linspace(-5, 5, 50).reshape(-1, 1)
y1=np.sin(X1.ravel()) +np.random.normal(0, 0.1, 50)
X2=np.linspace(0, 10, 100).reshape(-1, 1)
y2=np.sin(X2.ravel()) +np.random.normal(0, 0.2, 100)
# Create and fit multi-view modelmodel=EGGP(gen=150, nPop=200)
model.fit_mvsr([X1, X2], [y1, y2])
# Make predictions for each viewy_pred1=model.predict_mvsr(X1, view=0)
y_pred2=model.predict_mvsr(X2, view=1)

Integration with scikit-learn

fromsklearn.model_selectionimporttrain_test_splitfromsklearn.metricsimportmean_squared_errorfromeggpimportEGGP# Split dataX_train, X_test, y_train, y_test=train_test_split(X, y, test_size=0.2)
# Create and fit modelmodel=EGGP(gen=150, nPop=150, optIter=100)
model.fit(X_train, y_train)
# Evaluate on test sety_pred=model.predict(X_test)
mse=mean_squared_error(y_test, y_pred)
print(f"Test MSE: {mse}")

Parameters

ParameterTypeDefaultDescription
genint100Number of generations to run
nPopint100Population size
maxSizeint15Maximum allowed size for expressions (max 100)
nTournamentint3Tournament size for parent selection
pcfloat0.9Probability of performing crossover
pmfloat0.3Probability of performing mutation
nonterminalsstr"add,sub,mul,div"Comma-separated list of allowed functions
lossstr"MSE"Loss function: "MSE", "Gaussian", "Bernoulli", or "Poisson"
optIterint50Number of iterations for parameter optimization
optRepeatint2Number of restarts for parameter optimization
nParamsint-1Maximum number of parameters (-1 for unlimited)
splitint1Data splitting ratio for validation
simplifyboolFalseWhether to apply equality saturation to simplify expressions
dumpTostr""Filename to save the final e-graph
loadFromstr""Filename to load an e-graph to resume search

Available Functions

The following functions can be used in the nonterminals parameter:

  • Basic operations: add, sub, mul, div
  • Powers: power, powerabs, square, cube
  • Roots: sqrt, sqrtabs, cbrt
  • Trigonometric: sin, cos, tan, asin, acos, atan
  • Hyperbolic: sinh, cosh, tanh, asinh, acosh, atanh
  • Others: abs, log, logabs, exp, recip, aq (analytical quotient)

Methods

Core Methods

  • fit(X, y): Fits the symbolic regression model
  • predict(X): Generates predictions using the best model
  • score(X, y): Computes R² score of the best model

Multi-View Methods

  • fit_mvsr(Xs, ys): Fits a multi-view regression model
  • predict_mvsr(X, view): Generates predictions for a specific view
  • evaluate_best_model_view(X, view): Evaluates the best model on a specific view
  • evaluate_model_view(X, ix, view): Evaluates a specific model on a specific view

Utility Methods

  • evaluate_best_model(X): Evaluates the best model on the given data
  • evaluate_model(ix, X): Evaluates the model with index ix on the given data
  • get_model(idx): Returns a model function and its visual representation

Results

After fitting, the results attribute contains a pandas DataFrame with details about the discovered models, including:

  • Mathematical expressions
  • Model complexity
  • Parameter values
  • Error metrics
  • NumPy-compatible expressions

License

[LICENSE]

Citation

If you use EGGP in your research, please cite:

@inproceedings{eggp,
author = {de Franca, Fabricio Olivetti and Kronberger, Gabriel},
title = {Improving Genetic Programming for Symbolic Regression with Equality Graphs},
year = {2025},
isbn = {9798400714658},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
url = {https://doi.org/10.1145/3712256.3726383},
doi = {10.1145/3712256.3726383},
booktitle = {Proceedings of the Genetic and Evolutionary Computation Conference},
pages = {},
numpages = {9},
keywords = {Symbolic regression, Genetic programming, Equality saturation, Equality graphs},
location = {Malaga, Spain},
series = {GECCO '25},
archivePrefix = {arXiv},
eprint = {2501.17848},
primaryClass = {cs.LG}, }

Acknowledgments

The bindings were created following the amazing example written by wenkokke

Fabricio Olivetti de Franca is supported by Conselho Nacional de Desenvolvimento Cient'{i}fico e Tecnol'{o}gico (CNPq) grant 301596/2022-0.

Gabriel Kronberger is supported by the Austrian Federal Ministry for Climate Action, Environment, Energy, Mobility, Innovation and Technology, the Federal Ministry for Labour and Economy, and the regional government of Upper Austria within the COMET project ProMetHeus (904919) supported by the Austrian Research Promotion Agency (FFG).

About

Python wraper for eggp

Resources

Stars

16 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

eggp - e-graph GP

eggp (e-graph genetic programming), follows the same structure as the traditional GP. The initial population is created using ramped half-and-half respecting a maximum size and maximum depth parameter and, for a number of generations, it will choose two parents using tournament selection, apply the subtree crossover with probability $pc$ followed by the subtree mutation with probability $pm$, when the offsprings replace the current population following a dominance criteria.

The key differences of eggp are:

- new solutions are inserted into the e-graph followed by one step of equality saturation to find and store some of the equivalent expressions of the new offspring.
- the current population is replaced by the set of individuals formed by: the Pareto front, the next front after excluding the first Pareto-front, and a selection of the last offspring at random until it reaches the desired population size.
- the subtree crossover and mutation are modified to try to generate an unvisited exp

This repository provides a CLI and a Python package for eggp with a scikit-learn compatible API for symbolic regression.

Instructions:

CLI

How to use

eggp - E-graph Genetic Programming for Symbolic Regression.
Usage: eggp (-d|--dataset INPUT-FILE) [-t|--test ARG] [-g|--generations GENS]
(-s|--maxSize ARG) [-k|--split ARG] [--print-pareto] [--trace] [--loss ARG] [--opt-iter ARG] [--opt-retries ARG] [--number-params ARG] [--nPop ARG] [--tournament-size ARG] [--pc ARG] [--pm ARG] [--non-terminals ARG] [--dump-to ARG] [--load-from ARG] [--moo]
An implementation of GP with modified crossover and mutation operators
designed to exploit equality saturation and e-graphs.
https://arxiv.org/abs/2501.17848
Available options:
-d,--dataset INPUT-FILE CSV dataset.
-t,--test ARG test data (default: "")
-g,--generations GENS Number of generations. (default: 100)
-s,--maxSize ARG max-size.
-k,--split ARG k-split ratio training-validation (default: 1)
--print-pareto print Pareto front instead of best found expression
--trace print all evaluated expressions.
--loss ARG loss function: MSE, Gaussian, Poisson, Bernoulli.
(default: MSE)
--opt-iter ARG number of iterations in parameter optimization.
(default: 30)
--opt-retries ARG number of retries of parameter fitting. (default: 1)
--number-params ARG maximum number of parameters in the model. If this
argument is absent, the number is bounded by the
maximum size of the expression and there will be no
repeated parameter. (default: -1)
--nPop ARG population size (Default: 100). (default: 100)
--tournament-size ARG tournament size. (default: 2)
--pc ARG probability of crossover. (default: 1.0)
--pm ARG probability of mutation. (default: 0.3)
--non-terminals ARG set of non-terminals to use in the search.
(default: "Add,Sub,Mul,Div,PowerAbs,Recip")
--dump-to ARG dump final e-graph to a file. (default: "")
--load-from ARG load initial e-graph from a file. (default: "")
--moo replace the current population with the pareto front
instead of replacing it with the generated children.
-h,--help Show this help text

The dataset file must contain a header with each features name, and the --dataset and --test arguments can be accompanied by arguments separated by ':' following the format:

filename.ext:start_row:end_row:target:features

where each ':' field is optional. The fields are:

  • start_row:end_row is the range of the training rows (default 0:nrows-1). every other row not included in this range will be used as validation
  • target is either the name of the (if the datafile has headers) or the index of the target variable
  • features is a comma separated list of names or indices to be used as input variables of the regression model.

Example of valid names: dataset.csv, mydata.tsv, dataset.csv:20:100, dataset.tsv:20:100:price:m2,rooms,neighborhood, dataset.csv:::5:0,1,2.

The format of the file will be determined by the extension (e.g., csv, tsv,...). To use multi-view, simply pass multiple filenames in double-quotes:

eggp --dataset "dataset1.csv dataset2.csv dataset3.csv" ...

Installation

To install eggp you'll need:

  • libz
  • libnlopt
  • libgmp
  • ghc-9.6.6
  • cabal or stack

Method 1: PIP

Simply run:

pip install eggp 

under your Python environment.

Method 2: cabal

After installing the dependencies (e.g., apt install libz libnlopt libgmp), install ghcup

For Linux, macOS, FreeBSD or WSL2:

curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh

For Windows, run the following in a PowerShell:

Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; try { & ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1-UseBasicParsing))) -Interactive -DisableCurl } catch { Write-Error $_ }

After the installation, run ghcup tui and install the latest stack or cabal together with ghc-9.6.6 (select the items and press i). To install srsimplify simply run:

cabal install

Python

Features

  • Scikit-learn compatible API with fit() and predict() methods
  • Genetic programming approach with e-graph representation
  • Support for multi-view symbolic regressionsee here
  • Customizable evolutionary parameters (population size, tournament selection, etc.)
  • Flexible function set selection
  • Various loss functions for different problem types
  • Parameter optimization with multiple restarts
  • Optional expression simplification through equality saturation
  • Ability to save and load e-graphs

Usage

Basic Example

fromeggpimportEGGPimportnumpyasnp# Create sample dataX=np.linspace(-10, 10, 100).reshape(-1, 1)
y=2*X.ravel() +3*np.sin(X.ravel()) +np.random.normal(0, 1, 100)
# Create and fit the modelmodel=EGGP(gen=100, nonterminals="add,sub,mul,div,sin,cos")
model.fit(X, y)
# Make predictionsy_pred=model.predict(X)
# Examine the resultsprint(model.results)

Multi-View Symbolic Regression

fromeggpimportEGGPimportnumpyasnp# Create multiple views of dataX1=np.linspace(-5, 5, 50).reshape(-1, 1)
y1=np.sin(X1.ravel()) +np.random.normal(0, 0.1, 50)
X2=np.linspace(0, 10, 100).reshape(-1, 1)
y2=np.sin(X2.ravel()) +np.random.normal(0, 0.2, 100)
# Create and fit multi-view modelmodel=EGGP(gen=150, nPop=200)
model.fit_mvsr([X1, X2], [y1, y2])
# Make predictions for each viewy_pred1=model.predict_mvsr(X1, view=0)
y_pred2=model.predict_mvsr(X2, view=1)

Integration with scikit-learn

fromsklearn.model_selectionimporttrain_test_splitfromsklearn.metricsimportmean_squared_errorfromeggpimportEGGP# Split dataX_train, X_test, y_train, y_test=train_test_split(X, y, test_size=0.2)
# Create and fit modelmodel=EGGP(gen=150, nPop=150, optIter=100)
model.fit(X_train, y_train)
# Evaluate on test sety_pred=model.predict(X_test)
mse=mean_squared_error(y_test, y_pred)
print(f"Test MSE: {mse}")

Parameters

ParameterTypeDefaultDescription
genint100Number of generations to run
nPopint100Population size
maxSizeint15Maximum allowed size for expressions (max 100)
nTournamentint3Tournament size for parent selection
pcfloat0.9Probability of performing crossover
pmfloat0.3Probability of performing mutation
nonterminalsstr"add,sub,mul,div"Comma-separated list of allowed functions
lossstr"MSE"Loss function: "MSE", "Gaussian", "Bernoulli", or "Poisson"
optIterint50Number of iterations for parameter optimization
optRepeatint2Number of restarts for parameter optimization
nParamsint-1Maximum number of parameters (-1 for unlimited)
splitint1Data splitting ratio for validation
simplifyboolFalseWhether to apply equality saturation to simplify expressions
dumpTostr""Filename to save the final e-graph
loadFromstr""Filename to load an e-graph to resume search

Available Functions

The following functions can be used in the nonterminals parameter:

  • Basic operations: add, sub, mul, div
  • Powers: power, powerabs, square, cube
  • Roots: sqrt, sqrtabs, cbrt
  • Trigonometric: sin, cos, tan, asin, acos, atan
  • Hyperbolic: sinh, cosh, tanh, asinh, acosh, atanh
  • Others: abs, log, logabs, exp, recip, aq (analytical quotient)

Methods

Core Methods

  • fit(X, y): Fits the symbolic regression model
  • predict(X): Generates predictions using the best model
  • score(X, y): Computes R² score of the best model

Multi-View Methods

  • fit_mvsr(Xs, ys): Fits a multi-view regression model
  • predict_mvsr(X, view): Generates predictions for a specific view
  • evaluate_best_model_view(X, view): Evaluates the best model on a specific view
  • evaluate_model_view(X, ix, view): Evaluates a specific model on a specific view

Utility Methods

  • evaluate_best_model(X): Evaluates the best model on the given data
  • evaluate_model(ix, X): Evaluates the model with index ix on the given data
  • get_model(idx): Returns a model function and its visual representation

Results

After fitting, the results attribute contains a pandas DataFrame with details about the discovered models, including:

  • Mathematical expressions
  • Model complexity
  • Parameter values
  • Error metrics
  • NumPy-compatible expressions

License

[LICENSE]

Citation

If you use EGGP in your research, please cite:

@inproceedings{eggp,
author = {de Franca, Fabricio Olivetti and Kronberger, Gabriel},
title = {Improving Genetic Programming for Symbolic Regression with Equality Graphs},
year = {2025},
isbn = {9798400714658},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
url = {https://doi.org/10.1145/3712256.3726383},
doi = {10.1145/3712256.3726383},
booktitle = {Proceedings of the Genetic and Evolutionary Computation Conference},
pages = {},
numpages = {9},
keywords = {Symbolic regression, Genetic programming, Equality saturation, Equality graphs},
location = {Malaga, Spain},
series = {GECCO '25},
archivePrefix = {arXiv},
eprint = {2501.17848},
primaryClass = {cs.LG}, }

Acknowledgments

The bindings were created following the amazing example written by wenkokke

Fabricio Olivetti de Franca is supported by Conselho Nacional de Desenvolvimento Cient'{i}fico e Tecnol'{o}gico (CNPq) grant 301596/2022-0.

Gabriel Kronberger is supported by the Austrian Federal Ministry for Climate Action, Environment, Energy, Mobility, Innovation and Technology, the Federal Ministry for Labour and Economy, and the regional government of Upper Austria within the COMET project ProMetHeus (904919) supported by the Austrian Research Promotion Agency (FFG).

About

Python wraper for eggp

Resources

Stars

16 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

eggp - e-graph GP

eggp (e-graph genetic programming), follows the same structure as the traditional GP. The initial population is created using ramped half-and-half respecting a maximum size and maximum depth parameter and, for a number of generations, it will choose two parents using tournament selection, apply the subtree crossover with probability $pc$ followed by the subtree mutation with probability $pm$, when the offsprings replace the current population following a dominance criteria.

The key differences of eggp are:

- new solutions are inserted into the e-graph followed by one step of equality saturation to find and store some of the equivalent expressions of the new offspring.
- the current population is replaced by the set of individuals formed by: the Pareto front, the next front after excluding the first Pareto-front, and a selection of the last offspring at random until it reaches the desired population size.
- the subtree crossover and mutation are modified to try to generate an unvisited exp

This repository provides a CLI and a Python package for eggp with a scikit-learn compatible API for symbolic regression.

Instructions:

CLI

How to use

eggp - E-graph Genetic Programming for Symbolic Regression.
Usage: eggp (-d|--dataset INPUT-FILE) [-t|--test ARG] [-g|--generations GENS]
(-s|--maxSize ARG) [-k|--split ARG] [--print-pareto] [--trace] [--loss ARG] [--opt-iter ARG] [--opt-retries ARG] [--number-params ARG] [--nPop ARG] [--tournament-size ARG] [--pc ARG] [--pm ARG] [--non-terminals ARG] [--dump-to ARG] [--load-from ARG] [--moo]
An implementation of GP with modified crossover and mutation operators
designed to exploit equality saturation and e-graphs.
https://arxiv.org/abs/2501.17848
Available options:
-d,--dataset INPUT-FILE CSV dataset.
-t,--test ARG test data (default: "")
-g,--generations GENS Number of generations. (default: 100)
-s,--maxSize ARG max-size.
-k,--split ARG k-split ratio training-validation (default: 1)
--print-pareto print Pareto front instead of best found expression
--trace print all evaluated expressions.
--loss ARG loss function: MSE, Gaussian, Poisson, Bernoulli.
(default: MSE)
--opt-iter ARG number of iterations in parameter optimization.
(default: 30)
--opt-retries ARG number of retries of parameter fitting. (default: 1)
--number-params ARG maximum number of parameters in the model. If this
argument is absent, the number is bounded by the
maximum size of the expression and there will be no
repeated parameter. (default: -1)
--nPop ARG population size (Default: 100). (default: 100)
--tournament-size ARG tournament size. (default: 2)
--pc ARG probability of crossover. (default: 1.0)
--pm ARG probability of mutation. (default: 0.3)
--non-terminals ARG set of non-terminals to use in the search.
(default: "Add,Sub,Mul,Div,PowerAbs,Recip")
--dump-to ARG dump final e-graph to a file. (default: "")
--load-from ARG load initial e-graph from a file. (default: "")
--moo replace the current population with the pareto front
instead of replacing it with the generated children.
-h,--help Show this help text

The dataset file must contain a header with each features name, and the --dataset and --test arguments can be accompanied by arguments separated by ':' following the format:

filename.ext:start_row:end_row:target:features

where each ':' field is optional. The fields are:

  • start_row:end_row is the range of the training rows (default 0:nrows-1). every other row not included in this range will be used as validation
  • target is either the name of the (if the datafile has headers) or the index of the target variable
  • features is a comma separated list of names or indices to be used as input variables of the regression model.

Example of valid names: dataset.csv, mydata.tsv, dataset.csv:20:100, dataset.tsv:20:100:price:m2,rooms,neighborhood, dataset.csv:::5:0,1,2.

The format of the file will be determined by the extension (e.g., csv, tsv,...). To use multi-view, simply pass multiple filenames in double-quotes:

eggp --dataset "dataset1.csv dataset2.csv dataset3.csv" ...

Installation

To install eggp you'll need:

  • libz
  • libnlopt
  • libgmp
  • ghc-9.6.6
  • cabal or stack

Method 1: PIP

Simply run:

pip install eggp 

under your Python environment.

Method 2: cabal

After installing the dependencies (e.g., apt install libz libnlopt libgmp), install ghcup

For Linux, macOS, FreeBSD or WSL2:

curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh

For Windows, run the following in a PowerShell:

Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; try { & ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1-UseBasicParsing))) -Interactive -DisableCurl } catch { Write-Error $_ }

After the installation, run ghcup tui and install the latest stack or cabal together with ghc-9.6.6 (select the items and press i). To install srsimplify simply run:

cabal install

Python

Features

  • Scikit-learn compatible API with fit() and predict() methods
  • Genetic programming approach with e-graph representation
  • Support for multi-view symbolic regressionsee here
  • Customizable evolutionary parameters (population size, tournament selection, etc.)
  • Flexible function set selection
  • Various loss functions for different problem types
  • Parameter optimization with multiple restarts
  • Optional expression simplification through equality saturation
  • Ability to save and load e-graphs

Usage

Basic Example

fromeggpimportEGGPimportnumpyasnp# Create sample dataX=np.linspace(-10, 10, 100).reshape(-1, 1)
y=2*X.ravel() +3*np.sin(X.ravel()) +np.random.normal(0, 1, 100)
# Create and fit the modelmodel=EGGP(gen=100, nonterminals="add,sub,mul,div,sin,cos")
model.fit(X, y)
# Make predictionsy_pred=model.predict(X)
# Examine the resultsprint(model.results)

Multi-View Symbolic Regression

fromeggpimportEGGPimportnumpyasnp# Create multiple views of dataX1=np.linspace(-5, 5, 50).reshape(-1, 1)
y1=np.sin(X1.ravel()) +np.random.normal(0, 0.1, 50)
X2=np.linspace(0, 10, 100).reshape(-1, 1)
y2=np.sin(X2.ravel()) +np.random.normal(0, 0.2, 100)
# Create and fit multi-view modelmodel=EGGP(gen=150, nPop=200)
model.fit_mvsr([X1, X2], [y1, y2])
# Make predictions for each viewy_pred1=model.predict_mvsr(X1, view=0)
y_pred2=model.predict_mvsr(X2, view=1)

Integration with scikit-learn

fromsklearn.model_selectionimporttrain_test_splitfromsklearn.metricsimportmean_squared_errorfromeggpimportEGGP# Split dataX_train, X_test, y_train, y_test=train_test_split(X, y, test_size=0.2)
# Create and fit modelmodel=EGGP(gen=150, nPop=150, optIter=100)
model.fit(X_train, y_train)
# Evaluate on test sety_pred=model.predict(X_test)
mse=mean_squared_error(y_test, y_pred)
print(f"Test MSE: {mse}")

Parameters

ParameterTypeDefaultDescription
genint100Number of generations to run
nPopint100Population size
maxSizeint15Maximum allowed size for expressions (max 100)
nTournamentint3Tournament size for parent selection
pcfloat0.9Probability of performing crossover
pmfloat0.3Probability of performing mutation
nonterminalsstr"add,sub,mul,div"Comma-separated list of allowed functions
lossstr"MSE"Loss function: "MSE", "Gaussian", "Bernoulli", or "Poisson"
optIterint50Number of iterations for parameter optimization
optRepeatint2Number of restarts for parameter optimization
nParamsint-1Maximum number of parameters (-1 for unlimited)
splitint1Data splitting ratio for validation
simplifyboolFalseWhether to apply equality saturation to simplify expressions
dumpTostr""Filename to save the final e-graph
loadFromstr""Filename to load an e-graph to resume search

Available Functions

The following functions can be used in the nonterminals parameter:

  • Basic operations: add, sub, mul, div
  • Powers: power, powerabs, square, cube
  • Roots: sqrt, sqrtabs, cbrt
  • Trigonometric: sin, cos, tan, asin, acos, atan
  • Hyperbolic: sinh, cosh, tanh, asinh, acosh, atanh
  • Others: abs, log, logabs, exp, recip, aq (analytical quotient)

Methods

Core Methods

  • fit(X, y): Fits the symbolic regression model
  • predict(X): Generates predictions using the best model
  • score(X, y): Computes R² score of the best model

Multi-View Methods

  • fit_mvsr(Xs, ys): Fits a multi-view regression model
  • predict_mvsr(X, view): Generates predictions for a specific view
  • evaluate_best_model_view(X, view): Evaluates the best model on a specific view
  • evaluate_model_view(X, ix, view): Evaluates a specific model on a specific view

Utility Methods

  • evaluate_best_model(X): Evaluates the best model on the given data
  • evaluate_model(ix, X): Evaluates the model with index ix on the given data
  • get_model(idx): Returns a model function and its visual representation

Results

After fitting, the results attribute contains a pandas DataFrame with details about the discovered models, including:

  • Mathematical expressions
  • Model complexity
  • Parameter values
  • Error metrics
  • NumPy-compatible expressions

License

[LICENSE]

Citation

If you use EGGP in your research, please cite:

@inproceedings{eggp,
author = {de Franca, Fabricio Olivetti and Kronberger, Gabriel},
title = {Improving Genetic Programming for Symbolic Regression with Equality Graphs},
year = {2025},
isbn = {9798400714658},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
url = {https://doi.org/10.1145/3712256.3726383},
doi = {10.1145/3712256.3726383},
booktitle = {Proceedings of the Genetic and Evolutionary Computation Conference},
pages = {},
numpages = {9},
keywords = {Symbolic regression, Genetic programming, Equality saturation, Equality graphs},
location = {Malaga, Spain},
series = {GECCO '25},
archivePrefix = {arXiv},
eprint = {2501.17848},
primaryClass = {cs.LG}, }

Acknowledgments

The bindings were created following the amazing example written by wenkokke

Fabricio Olivetti de Franca is supported by Conselho Nacional de Desenvolvimento Cient'{i}fico e Tecnol'{o}gico (CNPq) grant 301596/2022-0.

Gabriel Kronberger is supported by the Austrian Federal Ministry for Climate Action, Environment, Energy, Mobility, Innovation and Technology, the Federal Ministry for Labour and Economy, and the regional government of Upper Austria within the COMET project ProMetHeus (904919) supported by the Austrian Research Promotion Agency (FFG).

About

Python wraper for eggp

Resources

Stars

16 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

eggp - e-graph GP

eggp (e-graph genetic programming), follows the same structure as the traditional GP. The initial population is created using ramped half-and-half respecting a maximum size and maximum depth parameter and, for a number of generations, it will choose two parents using tournament selection, apply the subtree crossover with probability $pc$ followed by the subtree mutation with probability $pm$, when the offsprings replace the current population following a dominance criteria.

The key differences of eggp are:

- new solutions are inserted into the e-graph followed by one step of equality saturation to find and store some of the equivalent expressions of the new offspring.
- the current population is replaced by the set of individuals formed by: the Pareto front, the next front after excluding the first Pareto-front, and a selection of the last offspring at random until it reaches the desired population size.
- the subtree crossover and mutation are modified to try to generate an unvisited exp

This repository provides a CLI and a Python package for eggp with a scikit-learn compatible API for symbolic regression.

Instructions:

CLI

How to use

eggp - E-graph Genetic Programming for Symbolic Regression.
Usage: eggp (-d|--dataset INPUT-FILE) [-t|--test ARG] [-g|--generations GENS]
(-s|--maxSize ARG) [-k|--split ARG] [--print-pareto] [--trace] [--loss ARG] [--opt-iter ARG] [--opt-retries ARG] [--number-params ARG] [--nPop ARG] [--tournament-size ARG] [--pc ARG] [--pm ARG] [--non-terminals ARG] [--dump-to ARG] [--load-from ARG] [--moo]
An implementation of GP with modified crossover and mutation operators
designed to exploit equality saturation and e-graphs.
https://arxiv.org/abs/2501.17848
Available options:
-d,--dataset INPUT-FILE CSV dataset.
-t,--test ARG test data (default: "")
-g,--generations GENS Number of generations. (default: 100)
-s,--maxSize ARG max-size.
-k,--split ARG k-split ratio training-validation (default: 1)
--print-pareto print Pareto front instead of best found expression
--trace print all evaluated expressions.
--loss ARG loss function: MSE, Gaussian, Poisson, Bernoulli.
(default: MSE)
--opt-iter ARG number of iterations in parameter optimization.
(default: 30)
--opt-retries ARG number of retries of parameter fitting. (default: 1)
--number-params ARG maximum number of parameters in the model. If this
argument is absent, the number is bounded by the
maximum size of the expression and there will be no
repeated parameter. (default: -1)
--nPop ARG population size (Default: 100). (default: 100)
--tournament-size ARG tournament size. (default: 2)
--pc ARG probability of crossover. (default: 1.0)
--pm ARG probability of mutation. (default: 0.3)
--non-terminals ARG set of non-terminals to use in the search.
(default: "Add,Sub,Mul,Div,PowerAbs,Recip")
--dump-to ARG dump final e-graph to a file. (default: "")
--load-from ARG load initial e-graph from a file. (default: "")
--moo replace the current population with the pareto front
instead of replacing it with the generated children.
-h,--help Show this help text

The dataset file must contain a header with each features name, and the --dataset and --test arguments can be accompanied by arguments separated by ':' following the format:

filename.ext:start_row:end_row:target:features

where each ':' field is optional. The fields are:

  • start_row:end_row is the range of the training rows (default 0:nrows-1). every other row not included in this range will be used as validation
  • target is either the name of the (if the datafile has headers) or the index of the target variable
  • features is a comma separated list of names or indices to be used as input variables of the regression model.

Example of valid names: dataset.csv, mydata.tsv, dataset.csv:20:100, dataset.tsv:20:100:price:m2,rooms,neighborhood, dataset.csv:::5:0,1,2.

The format of the file will be determined by the extension (e.g., csv, tsv,...). To use multi-view, simply pass multiple filenames in double-quotes:

eggp --dataset "dataset1.csv dataset2.csv dataset3.csv" ...

Installation

To install eggp you'll need:

  • libz
  • libnlopt
  • libgmp
  • ghc-9.6.6
  • cabal or stack

Method 1: PIP

Simply run:

pip install eggp 

under your Python environment.

Method 2: cabal

After installing the dependencies (e.g., apt install libz libnlopt libgmp), install ghcup

For Linux, macOS, FreeBSD or WSL2:

curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh

For Windows, run the following in a PowerShell:

Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; try { & ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1-UseBasicParsing))) -Interactive -DisableCurl } catch { Write-Error $_ }

After the installation, run ghcup tui and install the latest stack or cabal together with ghc-9.6.6 (select the items and press i). To install srsimplify simply run:

cabal install

Python

Features

  • Scikit-learn compatible API with fit() and predict() methods
  • Genetic programming approach with e-graph representation
  • Support for multi-view symbolic regressionsee here
  • Customizable evolutionary parameters (population size, tournament selection, etc.)
  • Flexible function set selection
  • Various loss functions for different problem types
  • Parameter optimization with multiple restarts
  • Optional expression simplification through equality saturation
  • Ability to save and load e-graphs

Usage

Basic Example

fromeggpimportEGGPimportnumpyasnp# Create sample dataX=np.linspace(-10, 10, 100).reshape(-1, 1)
y=2*X.ravel() +3*np.sin(X.ravel()) +np.random.normal(0, 1, 100)
# Create and fit the modelmodel=EGGP(gen=100, nonterminals="add,sub,mul,div,sin,cos")
model.fit(X, y)
# Make predictionsy_pred=model.predict(X)
# Examine the resultsprint(model.results)

Multi-View Symbolic Regression

fromeggpimportEGGPimportnumpyasnp# Create multiple views of dataX1=np.linspace(-5, 5, 50).reshape(-1, 1)
y1=np.sin(X1.ravel()) +np.random.normal(0, 0.1, 50)
X2=np.linspace(0, 10, 100).reshape(-1, 1)
y2=np.sin(X2.ravel()) +np.random.normal(0, 0.2, 100)
# Create and fit multi-view modelmodel=EGGP(gen=150, nPop=200)
model.fit_mvsr([X1, X2], [y1, y2])
# Make predictions for each viewy_pred1=model.predict_mvsr(X1, view=0)
y_pred2=model.predict_mvsr(X2, view=1)

Integration with scikit-learn

fromsklearn.model_selectionimporttrain_test_splitfromsklearn.metricsimportmean_squared_errorfromeggpimportEGGP# Split dataX_train, X_test, y_train, y_test=train_test_split(X, y, test_size=0.2)
# Create and fit modelmodel=EGGP(gen=150, nPop=150, optIter=100)
model.fit(X_train, y_train)
# Evaluate on test sety_pred=model.predict(X_test)
mse=mean_squared_error(y_test, y_pred)
print(f"Test MSE: {mse}")

Parameters

ParameterTypeDefaultDescription
genint100Number of generations to run
nPopint100Population size
maxSizeint15Maximum allowed size for expressions (max 100)
nTournamentint3Tournament size for parent selection
pcfloat0.9Probability of performing crossover
pmfloat0.3Probability of performing mutation
nonterminalsstr"add,sub,mul,div"Comma-separated list of allowed functions
lossstr"MSE"Loss function: "MSE", "Gaussian", "Bernoulli", or "Poisson"
optIterint50Number of iterations for parameter optimization
optRepeatint2Number of restarts for parameter optimization
nParamsint-1Maximum number of parameters (-1 for unlimited)
splitint1Data splitting ratio for validation
simplifyboolFalseWhether to apply equality saturation to simplify expressions
dumpTostr""Filename to save the final e-graph
loadFromstr""Filename to load an e-graph to resume search

Available Functions

The following functions can be used in the nonterminals parameter:

  • Basic operations: add, sub, mul, div
  • Powers: power, powerabs, square, cube
  • Roots: sqrt, sqrtabs, cbrt
  • Trigonometric: sin, cos, tan, asin, acos, atan
  • Hyperbolic: sinh, cosh, tanh, asinh, acosh, atanh
  • Others: abs, log, logabs, exp, recip, aq (analytical quotient)

Methods

Core Methods

  • fit(X, y): Fits the symbolic regression model
  • predict(X): Generates predictions using the best model
  • score(X, y): Computes R² score of the best model

Multi-View Methods

  • fit_mvsr(Xs, ys): Fits a multi-view regression model
  • predict_mvsr(X, view): Generates predictions for a specific view
  • evaluate_best_model_view(X, view): Evaluates the best model on a specific view
  • evaluate_model_view(X, ix, view): Evaluates a specific model on a specific view

Utility Methods

  • evaluate_best_model(X): Evaluates the best model on the given data
  • evaluate_model(ix, X): Evaluates the model with index ix on the given data
  • get_model(idx): Returns a model function and its visual representation

Results

After fitting, the results attribute contains a pandas DataFrame with details about the discovered models, including:

  • Mathematical expressions
  • Model complexity
  • Parameter values
  • Error metrics
  • NumPy-compatible expressions

License

[LICENSE]

Citation

If you use EGGP in your research, please cite:

@inproceedings{eggp,
author = {de Franca, Fabricio Olivetti and Kronberger, Gabriel},
title = {Improving Genetic Programming for Symbolic Regression with Equality Graphs},
year = {2025},
isbn = {9798400714658},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
url = {https://doi.org/10.1145/3712256.3726383},
doi = {10.1145/3712256.3726383},
booktitle = {Proceedings of the Genetic and Evolutionary Computation Conference},
pages = {},
numpages = {9},
keywords = {Symbolic regression, Genetic programming, Equality saturation, Equality graphs},
location = {Malaga, Spain},
series = {GECCO '25},
archivePrefix = {arXiv},
eprint = {2501.17848},
primaryClass = {cs.LG}, }

Acknowledgments

The bindings were created following the amazing example written by wenkokke

Fabricio Olivetti de Franca is supported by Conselho Nacional de Desenvolvimento Cient'{i}fico e Tecnol'{o}gico (CNPq) grant 301596/2022-0.

Gabriel Kronberger is supported by the Austrian Federal Ministry for Climate Action, Environment, Energy, Mobility, Innovation and Technology, the Federal Ministry for Labour and Economy, and the regional government of Upper Austria within the COMET project ProMetHeus (904919) supported by the Austrian Research Promotion Agency (FFG).

About

Python wraper for eggp

Resources

Stars

16 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

eggp - e-graph GP

eggp (e-graph genetic programming), follows the same structure as the traditional GP. The initial population is created using ramped half-and-half respecting a maximum size and maximum depth parameter and, for a number of generations, it will choose two parents using tournament selection, apply the subtree crossover with probability $pc$ followed by the subtree mutation with probability $pm$, when the offsprings replace the current population following a dominance criteria.

The key differences of eggp are:

- new solutions are inserted into the e-graph followed by one step of equality saturation to find and store some of the equivalent expressions of the new offspring.
- the current population is replaced by the set of individuals formed by: the Pareto front, the next front after excluding the first Pareto-front, and a selection of the last offspring at random until it reaches the desired population size.
- the subtree crossover and mutation are modified to try to generate an unvisited exp

This repository provides a CLI and a Python package for eggp with a scikit-learn compatible API for symbolic regression.

Instructions:

CLI

How to use

eggp - E-graph Genetic Programming for Symbolic Regression.
Usage: eggp (-d|--dataset INPUT-FILE) [-t|--test ARG] [-g|--generations GENS]
(-s|--maxSize ARG) [-k|--split ARG] [--print-pareto] [--trace] [--loss ARG] [--opt-iter ARG] [--opt-retries ARG] [--number-params ARG] [--nPop ARG] [--tournament-size ARG] [--pc ARG] [--pm ARG] [--non-terminals ARG] [--dump-to ARG] [--load-from ARG] [--moo]
An implementation of GP with modified crossover and mutation operators
designed to exploit equality saturation and e-graphs.
https://arxiv.org/abs/2501.17848
Available options:
-d,--dataset INPUT-FILE CSV dataset.
-t,--test ARG test data (default: "")
-g,--generations GENS Number of generations. (default: 100)
-s,--maxSize ARG max-size.
-k,--split ARG k-split ratio training-validation (default: 1)
--print-pareto print Pareto front instead of best found expression
--trace print all evaluated expressions.
--loss ARG loss function: MSE, Gaussian, Poisson, Bernoulli.
(default: MSE)
--opt-iter ARG number of iterations in parameter optimization.
(default: 30)
--opt-retries ARG number of retries of parameter fitting. (default: 1)
--number-params ARG maximum number of parameters in the model. If this
argument is absent, the number is bounded by the
maximum size of the expression and there will be no
repeated parameter. (default: -1)
--nPop ARG population size (Default: 100). (default: 100)
--tournament-size ARG tournament size. (default: 2)
--pc ARG probability of crossover. (default: 1.0)
--pm ARG probability of mutation. (default: 0.3)
--non-terminals ARG set of non-terminals to use in the search.
(default: "Add,Sub,Mul,Div,PowerAbs,Recip")
--dump-to ARG dump final e-graph to a file. (default: "")
--load-from ARG load initial e-graph from a file. (default: "")
--moo replace the current population with the pareto front
instead of replacing it with the generated children.
-h,--help Show this help text

The dataset file must contain a header with each features name, and the --dataset and --test arguments can be accompanied by arguments separated by ':' following the format:

filename.ext:start_row:end_row:target:features

where each ':' field is optional. The fields are:

  • start_row:end_row is the range of the training rows (default 0:nrows-1). every other row not included in this range will be used as validation
  • target is either the name of the (if the datafile has headers) or the index of the target variable
  • features is a comma separated list of names or indices to be used as input variables of the regression model.

Example of valid names: dataset.csv, mydata.tsv, dataset.csv:20:100, dataset.tsv:20:100:price:m2,rooms,neighborhood, dataset.csv:::5:0,1,2.

The format of the file will be determined by the extension (e.g., csv, tsv,...). To use multi-view, simply pass multiple filenames in double-quotes:

eggp --dataset "dataset1.csv dataset2.csv dataset3.csv" ...

Installation

To install eggp you'll need:

  • libz
  • libnlopt
  • libgmp
  • ghc-9.6.6
  • cabal or stack

Method 1: PIP

Simply run:

pip install eggp 

under your Python environment.

Method 2: cabal

After installing the dependencies (e.g., apt install libz libnlopt libgmp), install ghcup

For Linux, macOS, FreeBSD or WSL2:

curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh

For Windows, run the following in a PowerShell:

Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; try { & ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1-UseBasicParsing))) -Interactive -DisableCurl } catch { Write-Error $_ }

After the installation, run ghcup tui and install the latest stack or cabal together with ghc-9.6.6 (select the items and press i). To install srsimplify simply run:

cabal install

Python

Features

  • Scikit-learn compatible API with fit() and predict() methods
  • Genetic programming approach with e-graph representation
  • Support for multi-view symbolic regressionsee here
  • Customizable evolutionary parameters (population size, tournament selection, etc.)
  • Flexible function set selection
  • Various loss functions for different problem types
  • Parameter optimization with multiple restarts
  • Optional expression simplification through equality saturation
  • Ability to save and load e-graphs

Usage

Basic Example

fromeggpimportEGGPimportnumpyasnp# Create sample dataX=np.linspace(-10, 10, 100).reshape(-1, 1)
y=2*X.ravel() +3*np.sin(X.ravel()) +np.random.normal(0, 1, 100)
# Create and fit the modelmodel=EGGP(gen=100, nonterminals="add,sub,mul,div,sin,cos")
model.fit(X, y)
# Make predictionsy_pred=model.predict(X)
# Examine the resultsprint(model.results)

Multi-View Symbolic Regression

fromeggpimportEGGPimportnumpyasnp# Create multiple views of dataX1=np.linspace(-5, 5, 50).reshape(-1, 1)
y1=np.sin(X1.ravel()) +np.random.normal(0, 0.1, 50)
X2=np.linspace(0, 10, 100).reshape(-1, 1)
y2=np.sin(X2.ravel()) +np.random.normal(0, 0.2, 100)
# Create and fit multi-view modelmodel=EGGP(gen=150, nPop=200)
model.fit_mvsr([X1, X2], [y1, y2])
# Make predictions for each viewy_pred1=model.predict_mvsr(X1, view=0)
y_pred2=model.predict_mvsr(X2, view=1)

Integration with scikit-learn

fromsklearn.model_selectionimporttrain_test_splitfromsklearn.metricsimportmean_squared_errorfromeggpimportEGGP# Split dataX_train, X_test, y_train, y_test=train_test_split(X, y, test_size=0.2)
# Create and fit modelmodel=EGGP(gen=150, nPop=150, optIter=100)
model.fit(X_train, y_train)
# Evaluate on test sety_pred=model.predict(X_test)
mse=mean_squared_error(y_test, y_pred)
print(f"Test MSE: {mse}")

Parameters

ParameterTypeDefaultDescription
genint100Number of generations to run
nPopint100Population size
maxSizeint15Maximum allowed size for expressions (max 100)
nTournamentint3Tournament size for parent selection
pcfloat0.9Probability of performing crossover
pmfloat0.3Probability of performing mutation
nonterminalsstr"add,sub,mul,div"Comma-separated list of allowed functions
lossstr"MSE"Loss function: "MSE", "Gaussian", "Bernoulli", or "Poisson"
optIterint50Number of iterations for parameter optimization
optRepeatint2Number of restarts for parameter optimization
nParamsint-1Maximum number of parameters (-1 for unlimited)
splitint1Data splitting ratio for validation
simplifyboolFalseWhether to apply equality saturation to simplify expressions
dumpTostr""Filename to save the final e-graph
loadFromstr""Filename to load an e-graph to resume search

Available Functions

The following functions can be used in the nonterminals parameter:

  • Basic operations: add, sub, mul, div
  • Powers: power, powerabs, square, cube
  • Roots: sqrt, sqrtabs, cbrt
  • Trigonometric: sin, cos, tan, asin, acos, atan
  • Hyperbolic: sinh, cosh, tanh, asinh, acosh, atanh
  • Others: abs, log, logabs, exp, recip, aq (analytical quotient)

Methods

Core Methods

  • fit(X, y): Fits the symbolic regression model
  • predict(X): Generates predictions using the best model
  • score(X, y): Computes R² score of the best model

Multi-View Methods

  • fit_mvsr(Xs, ys): Fits a multi-view regression model
  • predict_mvsr(X, view): Generates predictions for a specific view
  • evaluate_best_model_view(X, view): Evaluates the best model on a specific view
  • evaluate_model_view(X, ix, view): Evaluates a specific model on a specific view

Utility Methods

  • evaluate_best_model(X): Evaluates the best model on the given data
  • evaluate_model(ix, X): Evaluates the model with index ix on the given data
  • get_model(idx): Returns a model function and its visual representation

Results

After fitting, the results attribute contains a pandas DataFrame with details about the discovered models, including:

  • Mathematical expressions
  • Model complexity
  • Parameter values
  • Error metrics
  • NumPy-compatible expressions

License

[LICENSE]

Citation

If you use EGGP in your research, please cite:

@inproceedings{eggp,
author = {de Franca, Fabricio Olivetti and Kronberger, Gabriel},
title = {Improving Genetic Programming for Symbolic Regression with Equality Graphs},
year = {2025},
isbn = {9798400714658},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
url = {https://doi.org/10.1145/3712256.3726383},
doi = {10.1145/3712256.3726383},
booktitle = {Proceedings of the Genetic and Evolutionary Computation Conference},
pages = {},
numpages = {9},
keywords = {Symbolic regression, Genetic programming, Equality saturation, Equality graphs},
location = {Malaga, Spain},
series = {GECCO '25},
archivePrefix = {arXiv},
eprint = {2501.17848},
primaryClass = {cs.LG}, }

Acknowledgments

The bindings were created following the amazing example written by wenkokke

Fabricio Olivetti de Franca is supported by Conselho Nacional de Desenvolvimento Cient'{i}fico e Tecnol'{o}gico (CNPq) grant 301596/2022-0.

Gabriel Kronberger is supported by the Austrian Federal Ministry for Climate Action, Environment, Energy, Mobility, Innovation and Technology, the Federal Ministry for Labour and Economy, and the regional government of Upper Austria within the COMET project ProMetHeus (904919) supported by the Austrian Research Promotion Agency (FFG).

About

Python wraper for eggp

Resources

Stars

16 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

eggp - e-graph GP

eggp (e-graph genetic programming), follows the same structure as the traditional GP. The initial population is created using ramped half-and-half respecting a maximum size and maximum depth parameter and, for a number of generations, it will choose two parents using tournament selection, apply the subtree crossover with probability $pc$ followed by the subtree mutation with probability $pm$, when the offsprings replace the current population following a dominance criteria.

The key differences of eggp are:

- new solutions are inserted into the e-graph followed by one step of equality saturation to find and store some of the equivalent expressions of the new offspring.
- the current population is replaced by the set of individuals formed by: the Pareto front, the next front after excluding the first Pareto-front, and a selection of the last offspring at random until it reaches the desired population size.
- the subtree crossover and mutation are modified to try to generate an unvisited exp

This repository provides a CLI and a Python package for eggp with a scikit-learn compatible API for symbolic regression.

Instructions:

CLI

How to use

eggp - E-graph Genetic Programming for Symbolic Regression.
Usage: eggp (-d|--dataset INPUT-FILE) [-t|--test ARG] [-g|--generations GENS]
(-s|--maxSize ARG) [-k|--split ARG] [--print-pareto] [--trace] [--loss ARG] [--opt-iter ARG] [--opt-retries ARG] [--number-params ARG] [--nPop ARG] [--tournament-size ARG] [--pc ARG] [--pm ARG] [--non-terminals ARG] [--dump-to ARG] [--load-from ARG] [--moo]
An implementation of GP with modified crossover and mutation operators
designed to exploit equality saturation and e-graphs.
https://arxiv.org/abs/2501.17848
Available options:
-d,--dataset INPUT-FILE CSV dataset.
-t,--test ARG test data (default: "")
-g,--generations GENS Number of generations. (default: 100)
-s,--maxSize ARG max-size.
-k,--split ARG k-split ratio training-validation (default: 1)
--print-pareto print Pareto front instead of best found expression
--trace print all evaluated expressions.
--loss ARG loss function: MSE, Gaussian, Poisson, Bernoulli.
(default: MSE)
--opt-iter ARG number of iterations in parameter optimization.
(default: 30)
--opt-retries ARG number of retries of parameter fitting. (default: 1)
--number-params ARG maximum number of parameters in the model. If this
argument is absent, the number is bounded by the
maximum size of the expression and there will be no
repeated parameter. (default: -1)
--nPop ARG population size (Default: 100). (default: 100)
--tournament-size ARG tournament size. (default: 2)
--pc ARG probability of crossover. (default: 1.0)
--pm ARG probability of mutation. (default: 0.3)
--non-terminals ARG set of non-terminals to use in the search.
(default: "Add,Sub,Mul,Div,PowerAbs,Recip")
--dump-to ARG dump final e-graph to a file. (default: "")
--load-from ARG load initial e-graph from a file. (default: "")
--moo replace the current population with the pareto front
instead of replacing it with the generated children.
-h,--help Show this help text

The dataset file must contain a header with each features name, and the --dataset and --test arguments can be accompanied by arguments separated by ':' following the format:

filename.ext:start_row:end_row:target:features

where each ':' field is optional. The fields are:

  • start_row:end_row is the range of the training rows (default 0:nrows-1). every other row not included in this range will be used as validation
  • target is either the name of the (if the datafile has headers) or the index of the target variable
  • features is a comma separated list of names or indices to be used as input variables of the regression model.

Example of valid names: dataset.csv, mydata.tsv, dataset.csv:20:100, dataset.tsv:20:100:price:m2,rooms,neighborhood, dataset.csv:::5:0,1,2.

The format of the file will be determined by the extension (e.g., csv, tsv,...). To use multi-view, simply pass multiple filenames in double-quotes:

eggp --dataset "dataset1.csv dataset2.csv dataset3.csv" ...

Installation

To install eggp you'll need:

  • libz
  • libnlopt
  • libgmp
  • ghc-9.6.6
  • cabal or stack

Method 1: PIP

Simply run:

pip install eggp 

under your Python environment.

Method 2: cabal

After installing the dependencies (e.g., apt install libz libnlopt libgmp), install ghcup

For Linux, macOS, FreeBSD or WSL2:

curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh

For Windows, run the following in a PowerShell:

Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; try { & ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1-UseBasicParsing))) -Interactive -DisableCurl } catch { Write-Error $_ }

After the installation, run ghcup tui and install the latest stack or cabal together with ghc-9.6.6 (select the items and press i). To install srsimplify simply run:

cabal install

Python

Features

  • Scikit-learn compatible API with fit() and predict() methods
  • Genetic programming approach with e-graph representation
  • Support for multi-view symbolic regressionsee here
  • Customizable evolutionary parameters (population size, tournament selection, etc.)
  • Flexible function set selection
  • Various loss functions for different problem types
  • Parameter optimization with multiple restarts
  • Optional expression simplification through equality saturation
  • Ability to save and load e-graphs

Usage

Basic Example

fromeggpimportEGGPimportnumpyasnp# Create sample dataX=np.linspace(-10, 10, 100).reshape(-1, 1)
y=2*X.ravel() +3*np.sin(X.ravel()) +np.random.normal(0, 1, 100)
# Create and fit the modelmodel=EGGP(gen=100, nonterminals="add,sub,mul,div,sin,cos")
model.fit(X, y)
# Make predictionsy_pred=model.predict(X)
# Examine the resultsprint(model.results)

Multi-View Symbolic Regression

fromeggpimportEGGPimportnumpyasnp# Create multiple views of dataX1=np.linspace(-5, 5, 50).reshape(-1, 1)
y1=np.sin(X1.ravel()) +np.random.normal(0, 0.1, 50)
X2=np.linspace(0, 10, 100).reshape(-1, 1)
y2=np.sin(X2.ravel()) +np.random.normal(0, 0.2, 100)
# Create and fit multi-view modelmodel=EGGP(gen=150, nPop=200)
model.fit_mvsr([X1, X2], [y1, y2])
# Make predictions for each viewy_pred1=model.predict_mvsr(X1, view=0)
y_pred2=model.predict_mvsr(X2, view=1)

Integration with scikit-learn

fromsklearn.model_selectionimporttrain_test_splitfromsklearn.metricsimportmean_squared_errorfromeggpimportEGGP# Split dataX_train, X_test, y_train, y_test=train_test_split(X, y, test_size=0.2)
# Create and fit modelmodel=EGGP(gen=150, nPop=150, optIter=100)
model.fit(X_train, y_train)
# Evaluate on test sety_pred=model.predict(X_test)
mse=mean_squared_error(y_test, y_pred)
print(f"Test MSE: {mse}")

Parameters

ParameterTypeDefaultDescription
genint100Number of generations to run
nPopint100Population size
maxSizeint15Maximum allowed size for expressions (max 100)
nTournamentint3Tournament size for parent selection
pcfloat0.9Probability of performing crossover
pmfloat0.3Probability of performing mutation
nonterminalsstr"add,sub,mul,div"Comma-separated list of allowed functions
lossstr"MSE"Loss function: "MSE", "Gaussian", "Bernoulli", or "Poisson"
optIterint50Number of iterations for parameter optimization
optRepeatint2Number of restarts for parameter optimization
nParamsint-1Maximum number of parameters (-1 for unlimited)
splitint1Data splitting ratio for validation
simplifyboolFalseWhether to apply equality saturation to simplify expressions
dumpTostr""Filename to save the final e-graph
loadFromstr""Filename to load an e-graph to resume search

Available Functions

The following functions can be used in the nonterminals parameter:

  • Basic operations: add, sub, mul, div
  • Powers: power, powerabs, square, cube
  • Roots: sqrt, sqrtabs, cbrt
  • Trigonometric: sin, cos, tan, asin, acos, atan
  • Hyperbolic: sinh, cosh, tanh, asinh, acosh, atanh
  • Others: abs, log, logabs, exp, recip, aq (analytical quotient)

Methods

Core Methods

  • fit(X, y): Fits the symbolic regression model
  • predict(X): Generates predictions using the best model
  • score(X, y): Computes R² score of the best model

Multi-View Methods

  • fit_mvsr(Xs, ys): Fits a multi-view regression model
  • predict_mvsr(X, view): Generates predictions for a specific view
  • evaluate_best_model_view(X, view): Evaluates the best model on a specific view
  • evaluate_model_view(X, ix, view): Evaluates a specific model on a specific view

Utility Methods

  • evaluate_best_model(X): Evaluates the best model on the given data
  • evaluate_model(ix, X): Evaluates the model with index ix on the given data
  • get_model(idx): Returns a model function and its visual representation

Results

After fitting, the results attribute contains a pandas DataFrame with details about the discovered models, including:

  • Mathematical expressions
  • Model complexity
  • Parameter values
  • Error metrics
  • NumPy-compatible expressions

License

[LICENSE]

Citation

If you use EGGP in your research, please cite:

@inproceedings{eggp,
author = {de Franca, Fabricio Olivetti and Kronberger, Gabriel},
title = {Improving Genetic Programming for Symbolic Regression with Equality Graphs},
year = {2025},
isbn = {9798400714658},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
url = {https://doi.org/10.1145/3712256.3726383},
doi = {10.1145/3712256.3726383},
booktitle = {Proceedings of the Genetic and Evolutionary Computation Conference},
pages = {},
numpages = {9},
keywords = {Symbolic regression, Genetic programming, Equality saturation, Equality graphs},
location = {Malaga, Spain},
series = {GECCO '25},
archivePrefix = {arXiv},
eprint = {2501.17848},
primaryClass = {cs.LG}, }

Acknowledgments

The bindings were created following the amazing example written by wenkokke

Fabricio Olivetti de Franca is supported by Conselho Nacional de Desenvolvimento Cient'{i}fico e Tecnol'{o}gico (CNPq) grant 301596/2022-0.

Gabriel Kronberger is supported by the Austrian Federal Ministry for Climate Action, Environment, Energy, Mobility, Innovation and Technology, the Federal Ministry for Labour and Economy, and the regional government of Upper Austria within the COMET project ProMetHeus (904919) supported by the Austrian Research Promotion Agency (FFG).

About

Python wraper for eggp

Resources

Stars

16 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages