1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
use crate::crossover::{self, Crossover, CrossoverConfig};
use crate::game;
use crate::mutation::{self, Mutation, MutationConfig};
use crate::tournaments;
#[cfg(not(test))]
pub mod default {
use super::*;
use crate::schedule_data;
// schedule_data.rs is automatically generated, hoist symbols
/// the number of genes. Genes are stored as unsigned integers from 0..NSYMS. Mapping these to meaningful real-world values is done in [schedule_data::SYMBOL_NAMES].
pub const NSYMS: usize = schedule_data::NSYMS;
/// the length of a chromosone.
pub const LENGTH: usize = schedule_data::LENGTH;
/// number of populations to optimize simultaneously
pub const THREADS: usize = 4;
/// the number of [Candidate]'s in a population.
pub const POPSIZE: usize = 200;
/// the minimum Hamming distance between two parents. Parents more closely related are not allowed to breed.
pub const TABOO_DISTANCE: usize = 5;
/// The [Tournament] and parameters to use both for ordering [Candidate]'s in a
/// population both in a generation cycle and selecting final winners. TBD: we
/// may want different tournaments in these two scenarios.
///
/// Note that even though Tournament is a trait, because this is a constant we
/// cannot set the type to `dyn Tournament` even though we would like to. So if
/// you change the value of this constant you'll also have to change the type.
/* pub const TOURNAMENT: tournaments::scale::Scale<
tournaments::single_elimination::SingleElimination<game::full::Full>,
> = tournaments::scale::Scale::new(
tournaments::single_elimination::SingleElimination::new(game::full::Full::new()),
1,
1.0,
2.0,
); */
pub const TOURNAMENT: tournaments::full_season::FullSeason<game::full::Full> =
tournaments::full_season::FullSeason::new(game::full::Full::new());
/// The list of [Crossover]'s that the algorithm can choose from, along with the
/// frequency of use.
///
/// Selection of the [Crossover] and [Mutation] algorithms is not done
/// stochastically. The algorithms are cycled respecting the weights. Therefore
/// if the sum of the weights in [CROSSOVER_CONFIG] have common factors with the
/// sum of the weights in [MUTATION_CONFIG], some combinations of crossover and
/// mutation may never be chosen. In some cases you may wish to deliberately
/// trigger this effect, but in most cases you should probably ensure that the
/// two sum of weights do not have a common factor.
pub const CROSSOVER_CONFIG: CrossoverConfig = CrossoverConfig::new(&[
(3, Crossover::Null),
(2, Crossover::Splice(crossover::splice::Splice::new())),
(2, Crossover::Mix(crossover::mix::Mix::new())),
]);
/// The list of [Mutation]'s that the algorithm can choose from, along with the
/// frequency of use.
///
/// Selection of the [Crossover] and [Mutation] algorithms is not done
/// stochastically. The algorithms are cycled respecting the weights. Therefore
/// if the sum of the weights in [CROSSOVER_CONFIG] have common factors with the
/// sum of the weights in [MUTATION_CONFIG], some combinations of crossover and
/// mutation may never be chosen. In some cases you may wish to deliberately
/// trigger this effect, but in most cases you should probably ensure that the
/// two sum of weights do not have a common factor.
pub const MUTATION_CONFIG: MutationConfig = MutationConfig::new(&[
(10, Mutation::Null),
(1, Mutation::Mutate(mutation::mutate::Mutate::new(1))),
(1, Mutation::Mutate(mutation::mutate::Mutate::new(2))),
(1, Mutation::Mutate(mutation::mutate::Mutate::new(3))),
(1, Mutation::Rotate(mutation::rotate::Rotate::new(1))),
(1, Mutation::Rotate(mutation::rotate::Rotate::new(2))),
(1, Mutation::Rotate(mutation::rotate::Rotate::new(3))),
]);
/*
/// All of the [FitnessFunction]'s used to score a [Candidate].
pub const FITNESS_CONFIG: FitnessConfig = FitnessConfig::new(&[
FitnessFunction::Distance(fitness::distance::Distance::new(
7,
schedule_data::DISTANCE_BEFORE,
[usize::MAX; NSYMS],
)),
FitnessFunction::ColorCount(fitness::color_count::ColorCount::new(
schedule_data::NCOLORS,
schedule_data::CHROMOSONE_COLORS,
schedule_data::COLOR_PREFS,
&schedule_data::COLOR_NAMES,
)),
FitnessFunction::WeightedCount(fitness::weighted_count::WeightedCount::new(
schedule_data::MAX_WEIGHT,
schedule_data::WEIGHTS,
)),
]);
/// All of the [Constraint]'s applied to a candidate. Theoretically any
/// [Candidate] that fails any constraint is invalid, but if the algorithm
/// doesn't assume that is possible. The algorithm considers any [Candidate]
/// with more [Constraint] violations than the minimum in the population to be
/// inferior.
pub const CONSTRAINT_CONFIG: ConstraintConfig =
ConstraintConfig::new(&[Constraint::InvalidPosition(
constraints::invalid_position::InvalidPosition::new(schedule_data::INVALID_POSITIONS),
)]);
*/
}
#[cfg(test)]
pub mod default {
use super::*;
pub const NSYMS: usize = 3;
pub const LENGTH: usize = 5;
pub const TABOO_DISTANCE: usize = 1;
pub const CROSSOVER_CONFIG: CrossoverConfig = CrossoverConfig::new(&[(1, Crossover::Null)]);
pub const MUTATION_CONFIG: MutationConfig =
MutationConfig::new(&[(1, Mutation::Mutate(mutation::mutate::Mutate::new(1)))]);
pub const FITNESS_CONFIG: FitnessConfig = FitnessConfig::new(&[FitnessFunction::Distance(
fitness::distance::Distance::new(7, [usize::MAX; 3], [usize::MAX; 3]),
)]);
pub const CONSTRAINT_CONFIG: ConstraintConfig = ConstraintConfig::new(&[]);
pub const TOURNAMENT: tournaments::single_elimination::SingleElimination<game::full::Full> =
tournaments::single_elimination::SingleElimination::new(game::full::Full::new());
}
/*
pub struct Config {
pub fitness: FitnessConfig,
pub constraints: ConstraintConfig,
}
impl Config {
pub fn current() -> Arc<Config> {
CURRENT_CONFIG.with(|c| c.read().unwrap().clone())
}
pub fn make_current(self) {
assert_eq!(default::FITNESS_CONFIG.nscores, self.fitness.nscores);
assert_eq!(
default::FITNESS_CONFIG.nscores,
FitnessConfig::nscores(self.fitness.functions)
);
CURRENT_CONFIG.with(|c| *c.write().unwrap() = Arc::new(self))
}
}
thread_local! {
static CURRENT_CONFIG: RwLock<Arc<Config>> = RwLock::new(Arc::new(
Config {
fitness: default::FITNESS_CONFIG,
constraints: default::CONSTRAINT_CONFIG,
}
)
);
}
*/