| 1 | module prime |
| 2 | |
| 3 | import rand |
| 4 | import toml |
| 5 | import os |
| 6 | |
| 7 | pub const toml_path = 'vlib/v/tests/bench/math_big_gcd/primes.toml' |
| 8 | |
| 9 | pub interface DataI { |
| 10 | to_primeset() PrimeSet |
| 11 | from_primeset(PrimeSet) DataI |
| 12 | } |
| 13 | |
| 14 | pub fn (di DataI) cast[T]() DataI { |
| 15 | return T{}.from_primeset(di.to_primeset()) |
| 16 | } |
| 17 | |
| 18 | pub type PrimeCfg = PrimeSet |
| 19 | |
| 20 | pub fn (pc PrimeCfg) short() string { |
| 21 | return "r: '${pc.r}' a: '${pc.a}' b: '${pc.b}'" |
| 22 | } |
| 23 | |
| 24 | @[heap] |
| 25 | pub struct PrimeSet { |
| 26 | pub mut: |
| 27 | r string @[required] |
| 28 | a string @[required] |
| 29 | b string @[required] |
| 30 | } |
| 31 | |
| 32 | pub fn (p PrimeSet) to_primeset() PrimeSet { |
| 33 | return p |
| 34 | } |
| 35 | |
| 36 | pub fn (p PrimeSet) from_primeset(ps PrimeSet) DataI { |
| 37 | return ps |
| 38 | } |
| 39 | |
| 40 | pub fn (p PrimeSet) predicate(pred fn (data PrimeSet) bool) bool { |
| 41 | return pred(p) |
| 42 | } |
| 43 | |
| 44 | pub fn (p PrimeSet) key() string { |
| 45 | return [p.r, p.a, p.b].join('.') |
| 46 | } |
| 47 | |
| 48 | pub fn (p PrimeSet) str() string { |
| 49 | return [p.r, p.a, p.b].join(' ') |
| 50 | } |
| 51 | |
| 52 | fn extract_count(s string) int { |
| 53 | digits := '0123456789'.split('') |
| 54 | if s == '' || !s.split('').any(it in digits) { |
| 55 | return 0 |
| 56 | } |
| 57 | ds := s.split('').filter(it in digits) |
| 58 | return ds.join('').int() |
| 59 | } |
| 60 | |
| 61 | // sizes lists the available names for prime-number sections. |
| 62 | pub fn sizes() []string { |
| 63 | primes := read_toml_file() |
| 64 | return primes.keys() |
| 65 | } |
| 66 | |
| 67 | // usage returns section-names and the count of available primes |
| 68 | // |
| 69 | pub fn usage() string { |
| 70 | primes := read_toml_file() |
| 71 | return sizes().map('${it}[..${primes[it].len}]').join('\n\t') |
| 72 | } |
| 73 | |
| 74 | // reads the Map[string] []string from disk |
| 75 | // and returns the parsed content |
| 76 | fn read_toml_file() map[string][]string { |
| 77 | fp := os.join_path(@VEXEROOT, toml_path) |
| 78 | |
| 79 | tm_doc := toml.parse_file(fp) or { |
| 80 | err_msg := 'expected ${fp}' |
| 81 | eprintln(err_msg) |
| 82 | panic(err) |
| 83 | } |
| 84 | // TODO: what happens if this goes wrong ? |
| 85 | tm_primes := tm_doc.value('primes') as map[string]toml.Any |
| 86 | |
| 87 | msg := 'expected a map[string][]string in TOML-data ? corrupt ?' |
| 88 | mut p := map[string][]string{} |
| 89 | for k in tm_primes.keys() { |
| 90 | p[k] = []string{} |
| 91 | arr := tm_primes[k] or { panic(msg) } |
| 92 | for _, elem in arr.array() { |
| 93 | p[k] << elem as string |
| 94 | } |
| 95 | } |
| 96 | return p |
| 97 | } |
| 98 | |
| 99 | pub fn random_list(cfg []string) []string { |
| 100 | primes := read_toml_file() |
| 101 | |
| 102 | mut p_list := []string{} |
| 103 | match cfg.len { |
| 104 | 1 { // prime-size e.g. 'xs' given |
| 105 | if cfg[0] !in primes { |
| 106 | return p_list |
| 107 | } else { |
| 108 | return primes[cfg[0]] |
| 109 | } |
| 110 | } |
| 111 | 2 { // prime-size and limiter given e.g 'xs.15' |
| 112 | prime_size := cfg[0] |
| 113 | if prime_size !in primes { |
| 114 | return p_list |
| 115 | } |
| 116 | |
| 117 | mut prime_count := extract_count(cfg[1]) |
| 118 | if prime_count == 0 { |
| 119 | return primes[prime_size] |
| 120 | } |
| 121 | mut num := '' |
| 122 | for prime_count != 0 { |
| 123 | num = primes[prime_size][rand.int_in_range(0, primes[prime_size].len - 1) or { 0 }] |
| 124 | if num in p_list { |
| 125 | continue |
| 126 | } |
| 127 | p_list << num |
| 128 | prime_count -= 1 |
| 129 | if prime_count >= primes[prime_size].len { |
| 130 | p_list = primes[prime_size] |
| 131 | break |
| 132 | } |
| 133 | } // eo-for |
| 134 | return p_list |
| 135 | } // cfg not understood |
| 136 | else { |
| 137 | return p_list |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | return p_list |
| 142 | } |
| 143 | |
| 144 | pub fn random_set(cfg PrimeCfg) ![]v.tests.bench.math_big_gcd.prime.PrimeSet { |
| 145 | p_lists := [ |
| 146 | cfg.r.split('.'), |
| 147 | cfg.a.split('.'), |
| 148 | cfg.b.split('.'), |
| 149 | ].map(random_list(it.map(it.trim_space().to_lower_ascii()))) |
| 150 | |
| 151 | // test for empty lists |
| 152 | // |
| 153 | if p_lists.any(it.len == 0) { |
| 154 | msg := [ |
| 155 | 'bad config was :\n\n"${cfg}"', |
| 156 | "maybe try e.g { r: 'l.5' a: 'xxl.5 b: 'xl.10' } makes a set of 250", |
| 157 | 'your config was { ${cfg.short()} }', |
| 158 | 'sizes ${usage()}\n', |
| 159 | ].join('\n\n') |
| 160 | |
| 161 | return error(msg) |
| 162 | } |
| 163 | // filter unique combinations thru map |
| 164 | // |
| 165 | mut tmp := map[string]PrimeSet{} |
| 166 | for r in p_lists[0] { |
| 167 | for a in p_lists[1] { |
| 168 | for b in p_lists[2] { |
| 169 | d := PrimeSet{r, a, b} |
| 170 | if d.key() in tmp { |
| 171 | continue |
| 172 | } |
| 173 | tmp[d.key()] = d |
| 174 | } |
| 175 | } |
| 176 | } |
| 177 | return tmp.keys().map(tmp[it]) |
| 178 | } |
| 179 | |