Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## Unreleased

* Fix: correct tournament selection to account for classifier numerosity ([#235](https://github.com/xcsf-dev/xcsf/pull/235))

## Version 1.4.10 (Sep 11, 2025)

Changes:
Expand Down
33 changes: 26 additions & 7 deletions xcsf/ea.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* @file ea.c
* @author Richard Preen <rpreen@gmail.com>
* @copyright The Authors.
* @date 2015--2023.
* @date 2015--2026.
* @brief Evolutionary algorithm functions.
*/

Expand Down Expand Up @@ -146,27 +146,46 @@
return iter->cl;
}

/**
* @brief Probability a classifier with numerosity num is selected.
* @param [in] num Numerosity of the classifier.
* @param [in] tau Tournament size (selection probability per copy).
* @return Selection probability: 1 - (1-tau)^num.
*/
static double
p_num_tau(const int num, const double tau)
{
return 1 - pow(1 - tau, (double) num);
}

/**
* @brief Selects a classifier from the set via tournament.
* @details Uses Algorithm 4 in Lanzi (2026)
* "On the implementation of tournament selection in XCS".
* @param [in] xcsf The XCSF data structure.
* @param [in] set The set to select from.
* @return A pointer to the selected classifier.
*/
static struct Cl *
ea_select_tournament(const struct XCSF *xcsf, const struct Set *set)
{
struct Cl *winner = NULL;
while (winner == NULL) {
const double tau = xcsf->ea->select_size;
struct Cl *clb = NULL;
while (clb == NULL) {
double maxf = 0;
const struct Clist *iter = set->list;
while (iter != NULL) {
if ((rand_uniform(0, 1) < xcsf->ea->select_size) &&
(winner == NULL || iter->cl->fit > winner->fit)) {
winner = iter->cl;
const double f = iter->cl->fit / iter->cl->num;
const int num = iter->cl->num;
if ((clb == NULL || f > maxf) &&
rand_uniform(0, 1) < p_num_tau(num, tau)) {
clb = iter->cl;
maxf = f;
}
iter = iter->next;
}
}
return winner;
return clb;
}

/**
Expand Down Expand Up @@ -381,7 +400,7 @@
if (type == EA_SELECT_TOURNAMENT) {
return EA_STRING_TOURNAMENT;
}
printf("ea_type_as_string(): invalid type: %d\n", type);

Check warning on line 403 in xcsf/ea.c

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

tainted value 'type' is leaking

See more on https://sonarcloud.io/project/issues?id=xcsf-dev_xcsf&issues=AaAQ28Pq90oxRtkidK0R&open=AaAQ28Pq90oxRtkidK0R&pullRequest=235
exit(EXIT_FAILURE);
}

Expand Down
Loading