aboutsummaryrefslogtreecommitdiff
path: root/srchr/src/main.rs
blob: db8a1032bbafad552483d623825f2e185f566b0b (plain)
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
// Copyright (C) 2022 tslil clingman
//
// This file is part of srchr.
//
// srchr is free software: you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// srchr is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with
// srchr. If not, see <https://www.gnu.org/licenses/>.

mod config;
mod corpus;
mod evaluation;
mod layout;
mod output;

use rayon::prelude::*;

use rand::prelude::*;
use rand_pcg::*;

use config::*;
use corpus::*;
use evaluation::*;
use layout::*;

use std::time::Instant;

struct Tournament<'a> {
    rngs: Vec<Pcg64>,
    top_prelayouts: Vec<(Prelayout, f32)>,
    corpus: &'a Corpus,
}

impl<'a> Tournament<'a> {
    fn new_from_seed_prelayout(seed_prelayout: &Prelayout, corpus: &'a Corpus) -> Tournament<'a> {
        let mut rngs: Vec<Pcg64> = Vec::new();
        for _ in 0..NUM_CONTESTANTS {
            rngs.push(Pcg64::from_entropy());
        }

        let mut top_prelayouts: Vec<(Prelayout, f32)> = Vec::new();
        let score = prelayout_fitness(&corpus, &seed_prelayout);
        for _ in 0..NUM_PERSIST {
            top_prelayouts.push((seed_prelayout.clone(), score));
        }

        Tournament {
            rngs,
            top_prelayouts,
            corpus,
        }
    }

    fn run_round(&mut self) -> Option<Prelayout> {
        let rngs = &mut self.rngs;

        let mut tournament = rngs
            .into_par_iter()
            .map(|mut rng| {
                let layout = Prelayout::new_random_from(
                    &self.top_prelayouts[rng.gen_range(0..NUM_PERSIST)].0,
                    &mut rng,
                );
                return (layout, prelayout_fitness(&self.corpus, &layout));
            })
            .collect::<Vec<(Prelayout, f32)>>();

        let best = self.top_prelayouts[0].1;
        tournament.append(&mut self.top_prelayouts);
        tournament.sort_by(|(_, lscore), (_, rscore)| {
            if lscore < rscore {
                std::cmp::Ordering::Less
            } else {
                std::cmp::Ordering::Greater
            }
        });

        let result;
        if tournament[0].1 + 1e-7 < best {
            result = Some(tournament[0].0);
        } else {
            result = None;
        }

        for i in 0..NUM_PERSIST {
            self.top_prelayouts.push(tournament[i]);
        }

        result
    }
}

fn main() {
    let corpus;
    if LOAD_STATS {
        corpus = Corpus::load_from_json_file(STATS_FILE_NAME).unwrap();
    } else {
        corpus = Corpus::load_from_text_file(CORPUS_FILE_NAME).unwrap();
    }

    let seed_layout = Layout::from_verbose(STARTING_LAYOUT_STRING).unwrap();
    let seed_evl = Evaluation::evaluate_layout(&corpus, &seed_layout);
    let seed_prelayout = seed_layout.as_prelayout();

    println!("Starting with\n{}{}", seed_layout, seed_evl);

    let mut tournament = Tournament::new_from_seed_prelayout(&seed_prelayout, &corpus);

    let mut count: usize = 0;
    let mut current = Instant::now();
    loop {
        let improvement = tournament.run_round();

        if let Some(prelayout) = improvement {
            let layout = Layout::from_prelayout(&prelayout, &corpus);
            let evl = Evaluation::evaluate_layout(&corpus, &layout);
            println!("\n================================================================================\n\n{}{}",
                 layout, evl
            );
        }

        count += 1;
        if count > 65535 {
            let duration = current.elapsed();
            let rps = count as f32 / duration.as_millis() as f32 * 1000.0;
            eprint!(
                "\u{001b}[2K\u{001b}[1000D{} layouts/s and {} tournaments/s",
                rps * NUM_CONTESTANTS as f32,
                rps
            );
            current = Instant::now();
            count = 0;
        }
    }
}