Customization¶
If you have explored the options and PySRRegressor reference, and still haven't figured out how to specify a constraint or objective required for your problem, you might consider editing the backend.
The backend of PySR is written as a pure Julia package under the name SymbolicRegression.jl.
This package is accessed with juliacall
, which allows us to transfer objects back and forth between the Python and Julia runtimes.
PySR gives you access to everything in SymbolicRegression.jl, but there are some specific use-cases which require modifications to the backend itself. Generally you can do this as follows:
1. Check out the source code¶
Clone a copy of the backend as well as PySR:
git clone https://github.com/MilesCranmer/SymbolicRegression.jl
git clone https://github.com/MilesCranmer/PySR
You may wish to check out the specific versions, which you can do with:
cd PySR
git checkout <version>
# You can see the current backend version in `pysr/juliapkg.json`
cd ../SymbolicRegression.jl
git checkout <backend_version>
2. Edit the source to your requirements¶
The main search code can be found in src/SymbolicRegression.jl
.
Here are some tips:
- The documentation for the backend is given here.
- Throughout the package, you will often see template functions which typically use a symbol
T
(such as in the stringwhere {T<:Real}
). Here,T
is simply the datatype of the input data and stored constants, such asFloat32
orFloat64
. Writing functions in this way lets us write functions generic to types, while still having access to the specific type specified at compilation time. - Expressions are stored as binary trees, using the
Node{T}
type, described here. - For reference, the main loop itself is found in the
equation_search
function insidesrc/SymbolicRegression.jl
. - Parts of the code which are typically edited by users include:
src/CheckConstraints.jl
, particularly the functioncheck_constraints
. This function checks whether a given expression satisfies constraints, such as having a complexity lower thanmaxsize
, and whether it contains any forbidden nestings of functions.- Note that all expressions, even intermediate expressions, must comply with constraints. Therefore, make sure that evolution can still reach your desired expression (with one mutation at a time), before setting a hard constraint. In other cases you might want to instead put in the loss function.
src/Options.jl
, as well as the struct definition insrc/OptionsStruct.jl
. This file specifies all the options used in the search: an instance ofOptions
is typically available throughout every function inSymbolicRegression.jl
. If you add new functionality to the backend, and wish to make it parameterizable (including from PySR), you should specify it in the options.
3. Let PySR use the modified backend¶
Once you have made your changes, you should edit the pysr/juliapkg.json
file
in the PySR repository to point to this local copy.
Do this by removing the "version"
key and adding a "dev"
and "path"
key:
...
"packages": {
"SymbolicRegression": {
"uuid": "8254be44-1295-4e6a-a16d-46603ac705cb",
"dev": true,
"path": "/path/to/SymbolicRegression.jl"
},
...
You can then install PySR with this modified backend by running:
For more information on juliapkg.json
, see pyjuliapkg
.
Additional notes¶
If you get comfortable enough with the backend, you might consider using the Julia package directly: the API is given on the SymbolicRegression.jl documentation.
If you make a change that you think could be useful to other users, don't hesitate to open a pull request on either the PySR or SymbolicRegression.jl repositories! Contributions are very appreciated.