genetic_planner/
genetic_planner.rs

1extern crate rand;
2use rand::Rand;
3use rand::Rng;
4
5use std::cmp::PartialEq;
6
7use genetic::*;
8
9pub trait State
10    where Self: Sized + Clone + Send + Sync + 'static
11{
12    /// Get the initial state
13    fn get_initial_state() -> Self;
14    /// Get a random action 
15    fn get_random_action() -> Action<Self>;
16    /// Verify if the current state is the goal
17    fn is_goal(&self) -> bool;
18    /// Get an aproximated distance to the goal state
19    fn get_heuristic(&self) -> i32;
20}
21
22/// Contains the actions of a Plan 
23pub struct Plan<T>
24    where T: State + Clone + Send + Sync + 'static
25{
26    /// State reached using the actions, the first state is
27    /// State::get_initial_state()
28    pub state: T,
29    /// Actions of the Plan
30    pub actions: Vec<Action<T>>,
31}
32
33impl<T> Plan<T>
34    where T: State + Clone
35{
36    /// Create a new Action
37    pub fn new(state: T) -> Plan<T> {
38        Plan {
39            state: state,
40            actions: Vec::new(),
41        }
42    }
43}
44
45/// Contains a function applicable to T and a name
46#[derive(Clone)]
47pub struct Action<T>
48    where T: State + Clone + Send + Sync + 'static
49{
50    pub action: fn(state: T) -> Option<T>,
51    pub name: String,
52}
53
54impl<T> Rand for Action<T>
55    where T: State + Clone
56{
57    fn rand<R: Rng>(_: &mut R) -> Action<T> {
58        T::get_random_action()
59    }
60}
61
62impl<T> PartialEq for Action<T>
63    where T: State + Clone + Send + Sync + 'static
64{
65    fn eq(&self, other: &Action<T>) -> bool {
66        self.name != other.name
67    }
68}
69
70/// Contains the configuration of the Planner 
71pub struct PlannerConfiguration {
72    /// Max number of actions
73    pub max_actions: usize,
74    /// Number of the Individual in the Population
75    pub population_size: usize,
76    /// Number of Individual to copy in the next generation
77    pub elitism_size: usize,
78    /// Size of the set used to select the parentof the offsprings
79    pub tournmant_size: usize,
80    /// Parameter used by the crossover function
81    pub uniform_rate: f32,
82    /// Parameter used by the mutate function
83    pub mutation_rate: f32,
84    /// Number of thread used in the evolve function
85    pub threadpool_size: usize,
86}
87
88/// Apply the Action of the Individual to the initial state
89fn apply_actions<T>(i: Individual<Action<T>>) -> Plan<T>
90    where T: State + Clone + Send + Sync + 'static
91{
92    let mut state = Some(T::get_initial_state());
93    let mut old_state = state.clone();
94    let mut used_actions: Vec<Action<T>> = Vec::new();
95    let mut actions = i.genes.iter();
96    let mut action = actions.next();
97    while action.is_some() && state.clone().is_some() && !state.clone().unwrap().is_goal() {
98        state = (action.clone().unwrap().action)(state.unwrap());
99        if state.clone().is_some() {
100            old_state = state.clone();
101            let tmp = action.clone().unwrap();
102            let last_action = Action {
103                action: tmp.action,
104                name: tmp.name.to_string(),
105            };
106            used_actions.push(last_action);
107            action = actions.next();
108        }
109    }
110    match state {
111        None => {
112            Plan {
113                state: old_state.unwrap(),
114                actions: used_actions,
115            }
116        }
117        Some(sstate) => {
118            Plan {
119                state: sstate,
120                actions: used_actions,
121            }
122        }
123    }
124}
125
126/// Calculate the fitness of an Individual<Action<T>>
127fn fitness_planner<T>(i: Individual<Action<T>>) -> i32
128    where T: State + Clone + Send + Sync + 'static
129{
130    let node = apply_actions(i);
131    -node.state.get_heuristic()
132}
133
134/// Convert PlannerConfiguration to PopulationConfiguration
135fn get_population_configuration<T>(c: PlannerConfiguration) -> PopulationConfiguration<Action<T>>
136    where T: State + Clone + Send + Sync + 'static
137{
138    PopulationConfiguration {
139        genenumber: c.max_actions,
140        population_size: c.population_size,
141        elitism_size: c.elitism_size,
142        tournmant_size: c.tournmant_size,
143        uniform_rate: c.uniform_rate,
144        mutation_rate: c.mutation_rate,
145        fitness: fitness_planner,
146        threadpool_size: c.threadpool_size,
147    }
148}
149
150/// Find a Plan and its Population starting a Population
151pub fn find_solution_and_population_from_population<T>(pop: Population<Action<T>>)
152                                                       -> (Plan<T>, Population<Action<T>>)
153    where T: State + Clone + Send + Sync + 'static
154{
155    let mut pop = pop.clone();
156    let mut best_actions = pop.get_fittest();
157    let mut node: Plan<T> = apply_actions(best_actions.unwrap().0);
158    while !node.state.is_goal() {
159        pop = pop.evolve();
160        best_actions = pop.get_fittest();
161        node = apply_actions(best_actions.unwrap().0);
162    }
163    (Plan {
164        state: node.state,
165        actions: node.actions,
166    },
167     pop)
168}
169
170/// Find a Plan and its Population
171pub fn find_solution_and_population<T>(c: PlannerConfiguration) -> (Plan<T>, Population<Action<T>>)
172    where T: State + Clone + Send + Sync + 'static
173{
174    let pc = get_population_configuration(c);
175    let pop = Population::new(pc);
176    find_solution_and_population_from_population(pop)
177}
178
179/// Find a plan 
180pub fn find_solution<T>(c: PlannerConfiguration) -> Plan<T>
181    where T: State + Clone + Send + Sync + 'static
182{
183    find_solution_and_population(c).0
184}
185
186/// Find a plan starting from a Population
187pub fn find_solution_from_population<T>(pop: Population<Action<T>>) -> Plan<T>
188    where T: State + Clone + Send + Sync + 'static
189{
190    find_solution_and_population_from_population(pop).0
191}
192
193/// Found the best plan and its Population, after <iterations> iterations
194pub fn find_best_and_population_after_iterations_from_population<T>
195    (pop: Population<Action<T>>,
196     iterations: usize)
197     -> (Plan<T>, Population<Action<T>>)
198    where T: State + Clone + Send + Sync + 'static
199{
200    let mut pop = pop.clone();
201    for _ in 0..iterations {
202        pop = pop.evolve();
203    }
204    let best_actions = pop.get_fittest();
205    let node = apply_actions(best_actions.unwrap().0);
206    (Plan {
207        state: node.state,
208        actions: node.actions,
209    },
210     pop)
211}
212
213/// Found the best plan and its Population after <iterations> iterations
214pub fn find_best_and_population_after_iterations<T>(c: PlannerConfiguration,
215                                                    iterations: usize)
216                                                    -> (Plan<T>, Population<Action<T>>)
217    where T: State + Clone + Send + Sync + 'static
218{
219    let pc = get_population_configuration(c);
220    let pop = Population::new(pc);
221    find_best_and_population_after_iterations_from_population(pop, iterations)
222}
223
224/// Found the best plan after <iterations> iterations
225pub fn find_best_after_iterations<T>(c: PlannerConfiguration, iterations: usize) -> Plan<T>
226    where T: State + Clone + Send + Sync + 'static
227{
228    find_best_and_population_after_iterations(c, iterations).0
229}
230
231/// Found the best plan after <iterations> iterations starting from a Population
232pub fn find_best_after_iterations_from_population<T>(pop: Population<Action<T>>,
233                                                     iterations: usize)
234                                                     -> Plan<T>
235    where T: State + Clone + Send + Sync + 'static
236{
237    find_best_and_population_after_iterations_from_population(pop, iterations).0
238}