Documentation - xcsf-dev/xcsf GitHub Wiki
Directory Structure
buildempty folder to be used for building executablescfgcontains configuration files for initialising parameters for the stand-alone executabledoccontains files for generating Doxygen documentationenvcontains data files for problem environmentslibcontains third-party libraries for random number generation, unit testing, pybind, etc.pythoncontains example Python scriptspython/notebookscontains jupyter notebook examplestestcontains standard (C library) teststest/pythoncontains Python library testsxcsfcontains XCSF source codexcsf/utilscontains Python utilities for visualisation, etc.
Doxygen + graphviz
To build locally see Compiling and Running.
The github-pages contains prebuilt documentation, including:
Source Code Flow Chart
Below shows a simplified flow chart of the source code to help get started.
Note that xcsf.h contains the main data structure XCSF and is included in almost all files. See the call graphs in the documentation for further details.
graph TD;
main[pybind_wrapper.cpp / main.c] --> xcs[xcs_supervised.h / xcs_rl.h] & param.h;
xcs --> ea.h & clset.h & pa.h & loss.h;
clset.h --> cl.h;
ea.h --> cl.h;
pa.h --> cl.h;
cl.h --> condition.h & action.h & prediction.h & loss.h;
prediction.h --> pred[pred_rls.h / etc.] & pred_neural.h
condition.h --> cond[cond_rectangle.h / etc.] & cond_gp.h & cond_dgp.h & cond_neural.h;
action.h --> act_integer.h & act_neural.h;
pred_neural.h --> neural.h;
act_neural.h --> neural.h;
cond_neural.h --> neural.h;
cond_gp.h --> gp.h;
cond_dgp.h --> dgp.h;
Parameters
The main data structure XCSF located within xcsf.h is passed to almost all functions, enabling access to parameters. This structure directly contains general parameters, e.g., double BETA; which can be accessed with xcsf->BETA. It also contains sub-structures containing groups of parameters, e.g., for the EA with struct ArgsEA *ea;
The sub-structures containing groups of parameters are:
- Condition parameters defined within
struct ArgsCondlocated withincondition.h. - Action parameters defined within
struct ArgsActlocated withinaction.h. - Prediction parameters defined within
struct ArgsPredlocated withinprediction.h. - EA parameters defined within
struct ArgsEAlocated withinea.h.
Every parameter needs the following tasks implemented:
- setting the parameter value - this provides a single point at which the values change and minimums and maximums can be defined to help users and avoid undefined behaviour;
- setting the default parameter value;
- exporting the parameter as a JSON formatted string;
- importing the parameter with a JSON string;
- printing the parameter value (using the JSON export function);
- saving the parameter value to persistent storage;
- loading the parameter value from persistent storage;
These functions for general parameters are defined within param.c. For the above-mentioned sub-structures, the functions are located within the respective *.c files. These can then be accessed through the XCSF structure, e.g., xcsf->cond->bits.
Finally, to enable the parameters to be set by Python, they may also need to be added to pybind_wrapper.cpp.
Scikit-learn
The Python scikit-learn package requires the memory address of parameter values
to match between calls to set_params() and get_params() so to facilitate this the following approach has
been taken within pybind_wrapper.cpp. This approach has the benefit that both the stand-alone executable and
the Python library use the same JSON parsing functions to set parameters and parameters do not have to be
individually declared in the Python library constructor. Any future language interfaces (such as for Julia)
would also benefit from this.
def __init__(**kwargs) -> None: ...
- Constructor sets parameter values to defaults internally, including
x_dim=1, y_dim=1, n_actions=1; - These internal parameters are exported via JSON and used to update an exposed
paramsdict; - If any
kwargsare specified,set_params()is automatically called (see below);
def set_params(**kwargs) -> xcsf.XCS: ...
kwargsare imported internally via JSON;paramsdict is updated directly with thekwargs(no JSON export);
def get_params() -> dict: ...
- Returns the exposed
paramsdict;
def internal_params() -> dict: ...
- Returns the exported internal parameters via JSON as a dict;
Extending Classifiers
Despite being in C, classifiers are structured in an OO style via the use of virtual functions.
The classifier data structure Cl is located in xcsf.h and contains pointers to both data structures and virtual method tables (which hold pointers to the functions that operate on those data structures) for conditions, actions, and predictions. For conditions, the virtual table that defines the interface is located in condition.h as CondVtbl and all implementations of conditions must implement these functions. Switching between different condition implementations via hyperparameters is performed in condition.c. Similar functionality for actions is performed in action.h and action.c, likewise for predictions in prediction.h and prediction.c.
Functions operating on individual classifiers are implemented in cl.c and these functions can therefore call the abstract functions. For example, cond_match() will invoke an implementation such as cond_rectangle_match() or cond_neural_match() depending on which has been specified through the hyperparameters.
Version Numbering
Version number format: MAJOR.MINOR.PATCH - specified in xcsf.h, CMakeLists.txt and setup.py.
From v1.3.0 onwards, semantic versioning will be used:
MAJORversion: Increment the MAJOR version when you make incompatible API changes or introduce significant changes that might break existing functionality. These changes typically involve removing or changing existing APIs or adding new features that are not backward compatible.MINORversion: Increment the MINOR version when you add new features or functionalities in a backward-compatible manner. This means that existing APIs remain intact, and users can upgrade to the new version without making changes to their code.PATCHversion: Increment the PATCH version for backward-compatible bug fixes or minor improvements that do not affect the existing APIs significantly. These updates should not introduce any new features or break existing functionality.