tasks_generator 0.5 → 1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +13 -5
- data/ext/tasks_generator/bindings.cc +84 -52
- data/ext/tasks_generator/config.h +62 -26
- data/ext/tasks_generator/generator.h +162 -19
- data/ext/tasks_generator/question.h +20 -28
- data/ext/tasks_generator/question_shaker.h +62 -0
- data/ext/tasks_generator/topic.h +31 -0
- data/ext/tasks_generator/variants.h +200 -0
- data/lib/tasks_generator/version.rb +1 -1
- metadata +12 -14
- data/ext/tasks_generator/function.cc +0 -147
- data/ext/tasks_generator/function.h +0 -22
- data/ext/tasks_generator/generator.cc +0 -23
- data/ext/tasks_generator/theme.h +0 -42
- data/ext/tasks_generator/types.h +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NDA0NjJhMmY0YWEzY2VmYzA0M2Q1YjU0MzA4NTNhZWQwNjFiOWNiYg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YmJiMTZhYTZlMjQyODk0YmI5ZjM0MmZlOWU2NjE5Y2ExZjM2ZjM5OQ==
|
5
7
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MTcyMDk2ZTg5ZTI4NTM3ZmI2ZWU2NzdlNDE3ZTMwNWFhZWI4MzhmNzA2NWU3
|
10
|
+
YmY5ZmJjOTMxMjY5NjMzNWQyNzA3YWNlY2VmYzAxMjY5MTljYmIyMDhjNmMx
|
11
|
+
OTc5N2NmY2ZiZTk0OTczNjIyNWJhNDAxNWM0OGZlZDZkOGRjY2I=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MzA4ODU4YzBmMDMzZWJhMWYzZWJmOThkNWYxYjQ5YjVhYmRjZWE5YjhhZjAx
|
14
|
+
MDA4OWM1MDc3ZmYxNzFmYjIwNDY0ZjZkMjFlY2EyYWI2NDhiYzdlMTAwNGY1
|
15
|
+
OWZlYTE5YTdhMzI2MGU3MGJiOGUyNThjNDYwODU4NTcxYTA0Nzc=
|
@@ -5,17 +5,18 @@
|
|
5
5
|
#include "config.h"
|
6
6
|
#include "generator.h"
|
7
7
|
#include "question.h"
|
8
|
-
#include "
|
8
|
+
#include "topic.h"
|
9
9
|
|
10
|
-
using namespace
|
10
|
+
using namespace ailab;
|
11
11
|
|
12
12
|
template<>
|
13
13
|
question_t from_ruby<question_t>(Rice::Object obj) {
|
14
14
|
size_t qid = from_ruby<size_t>(obj.call("question_id"));
|
15
|
-
size_t tid = from_ruby<size_t>(obj.call("
|
15
|
+
size_t tid = from_ruby<size_t>(obj.call("topic_id"));
|
16
16
|
size_t d = from_ruby<size_t>(obj.call("difficulty"));
|
17
|
+
std::string t = from_ruby<std::string>(obj.call("text"));
|
17
18
|
|
18
|
-
return question_t(qid, tid, d);
|
19
|
+
return question_t(qid, tid, d, t);
|
19
20
|
}
|
20
21
|
|
21
22
|
template<>
|
@@ -45,30 +46,48 @@ Rice::Object to_ruby(std::vector<question_t> const &questions) {
|
|
45
46
|
}
|
46
47
|
|
47
48
|
template<>
|
48
|
-
|
49
|
-
size_t id = from_ruby<size_t>(obj.call("
|
50
|
-
size_t
|
51
|
-
|
49
|
+
topic_t from_ruby<topic_t>(Rice::Object obj) {
|
50
|
+
size_t id = from_ruby<size_t>(obj.call("topic_id"));
|
51
|
+
size_t pid = from_ruby<size_t>(obj.call("parent_id"));
|
52
|
+
std::string text = from_ruby<std::string>(obj.call("text"));
|
52
53
|
|
53
|
-
return
|
54
|
+
return topic_t(id, pid, text);
|
54
55
|
}
|
55
56
|
|
56
57
|
template<>
|
57
|
-
Rice::Object to_ruby<
|
58
|
-
return Rice::Data_Object<
|
58
|
+
Rice::Object to_ruby<topic_t>(topic_t const &th) {
|
59
|
+
return Rice::Data_Object<topic_t>(new topic_t(th));
|
59
60
|
}
|
60
61
|
|
61
62
|
template<>
|
62
|
-
std::vector<
|
63
|
+
std::vector<topic_t> from_ruby<std::vector<topic_t>>(Rice::Object obj) {
|
63
64
|
Rice::Array arr(obj);
|
64
65
|
|
65
|
-
std::vector<
|
66
|
-
|
66
|
+
std::vector<topic_t> topics;
|
67
|
+
topics.reserve(arr.size());
|
67
68
|
|
68
69
|
for (Rice::Object obj : arr)
|
69
|
-
|
70
|
+
topics.push_back(from_ruby<topic_t>(obj));
|
70
71
|
|
71
|
-
return
|
72
|
+
return topics;
|
73
|
+
}
|
74
|
+
|
75
|
+
template<>
|
76
|
+
Rice::Object to_ruby<std::vector<size_t>>(std::vector<size_t> const &v) {
|
77
|
+
return Rice::Data_Object<std::vector<size_t>>(new std::vector<size_t>(v));
|
78
|
+
}
|
79
|
+
|
80
|
+
template<>
|
81
|
+
std::vector<size_t> from_ruby<std::vector<size_t>>(Rice::Object obj) {
|
82
|
+
Rice::Array arr(obj);
|
83
|
+
|
84
|
+
std::vector<size_t> result;
|
85
|
+
result.reserve(arr.size());
|
86
|
+
|
87
|
+
for (Rice::Object obj : arr)
|
88
|
+
result.push_back(from_ruby<size_t>(obj));
|
89
|
+
|
90
|
+
return result;
|
72
91
|
}
|
73
92
|
|
74
93
|
void set_life_time(Rice::Object obj, size_t life_time) {
|
@@ -95,25 +114,33 @@ size_t get_population_size(Rice::Object obj) {
|
|
95
114
|
return Rice::Data_Object<config_t>(obj)->population_size;
|
96
115
|
}
|
97
116
|
|
98
|
-
void
|
99
|
-
Rice::Data_Object<config_t>(obj)->
|
117
|
+
void set_variants_count(Rice::Object obj, size_t variants_count) {
|
118
|
+
Rice::Data_Object<config_t>(obj)->variants_count = variants_count;
|
119
|
+
}
|
120
|
+
|
121
|
+
size_t get_variants_count(Rice::Object obj) {
|
122
|
+
return Rice::Data_Object<config_t>(obj)->variants_count;
|
123
|
+
}
|
124
|
+
|
125
|
+
void set_questions_count(Rice::Object obj, size_t questions_count) {
|
126
|
+
Rice::Data_Object<config_t>(obj)->questions_count = questions_count;
|
100
127
|
}
|
101
128
|
|
102
|
-
size_t
|
103
|
-
return Rice::Data_Object<config_t>(obj)->
|
129
|
+
size_t get_questions_count(Rice::Object obj) {
|
130
|
+
return Rice::Data_Object<config_t>(obj)->questions_count;
|
104
131
|
}
|
105
132
|
|
106
|
-
void
|
107
|
-
std::vector<
|
108
|
-
Rice::Data_Object<config_t>(obj)->
|
133
|
+
void set_topics(Rice::Object obj, Rice::Array topics) {
|
134
|
+
std::vector<size_t> th = from_ruby<std::vector<size_t>>(topics);
|
135
|
+
Rice::Data_Object<config_t>(obj)->topics = std::move(th);
|
109
136
|
}
|
110
137
|
|
111
|
-
Rice::Array
|
112
|
-
std::vector<
|
138
|
+
Rice::Array get_topics(Rice::Object obj) {
|
139
|
+
std::vector<size_t> const &topics = Rice::Data_Object<config_t>(obj)->topics;
|
113
140
|
|
114
141
|
Rice::Array arr;
|
115
|
-
for (
|
116
|
-
arr.push(to_ruby<
|
142
|
+
for (size_t t : topics)
|
143
|
+
arr.push(to_ruby<size_t>(t));
|
117
144
|
|
118
145
|
return arr;
|
119
146
|
}
|
@@ -125,8 +152,9 @@ config_t from_ruby<config_t>(Rice::Object obj) {
|
|
125
152
|
result.life_time = from_ruby<size_t>(obj.call("life_time"));
|
126
153
|
result.mutation_chance = from_ruby<double>(obj.call("mutation_chance"));
|
127
154
|
result.population_size = from_ruby<size_t>(obj.call("population_size"));
|
128
|
-
result.
|
129
|
-
result.
|
155
|
+
result.variants_count = from_ruby<size_t>(obj.call("variants_count"));
|
156
|
+
result.questions_count = from_ruby<size_t>(obj.call("questions_count"));
|
157
|
+
result.topics = from_ruby<std::vector<size_t>>(obj.call("topics"));
|
130
158
|
|
131
159
|
return result;
|
132
160
|
}
|
@@ -139,9 +167,10 @@ Rice::Object to_ruby<config_t>(config_t const &cnf) {
|
|
139
167
|
template<>
|
140
168
|
generator_t from_ruby<generator_t>(Rice::Object obj) {
|
141
169
|
config_t config = from_ruby<config_t>(obj.call("config"));
|
170
|
+
std::vector<topic_t> topics = from_ruby<std::vector<topic_t>>(obj.call("topics"));
|
142
171
|
std::vector<question_t> questions = from_ruby<std::vector<question_t>>(obj.call("questions"));
|
143
172
|
|
144
|
-
return generator_t(std::move(config), std::move(questions));
|
173
|
+
return generator_t(std::move(config), std::move(topics), std::move(questions));
|
145
174
|
}
|
146
175
|
|
147
176
|
template<>
|
@@ -150,9 +179,10 @@ Rice::Object to_ruby(generator_t const &t) {
|
|
150
179
|
}
|
151
180
|
|
152
181
|
template<>
|
153
|
-
Rice::Object to_ruby<
|
182
|
+
Rice::Object to_ruby<variants_t>(variants_t const &ans) {
|
183
|
+
std::vector<std::vector<question_t>> const &questions = ans.get_questions();
|
154
184
|
Rice::Array result;
|
155
|
-
for (std::vector<question_t> const &arr :
|
185
|
+
for (std::vector<question_t> const &arr : questions) {
|
156
186
|
Rice::Array buffer;
|
157
187
|
for (question_t const &q : arr)
|
158
188
|
buffer.push(to_ruby<question_t>(q));
|
@@ -165,36 +195,38 @@ extern "C" void Init_tasks_generator() {
|
|
165
195
|
Rice::Module rb_mTasksGenerator = Rice::define_module("TasksGenerator");
|
166
196
|
|
167
197
|
Rice::Data_Type<config_t> rb_cConfig = Rice::define_class_under<config_t>(rb_mTasksGenerator, "Config")
|
168
|
-
.define_constructor(Rice::Constructor<config_t, size_t>(),
|
198
|
+
.define_constructor(Rice::Constructor<config_t, size_t, size_t>(),
|
199
|
+
(Rice::Arg("variants_count") = 8, Rice::Arg("questions_count") = 8))
|
169
200
|
.define_method("life_time=", &set_life_time)
|
170
201
|
.define_method("mutation_chance=", &set_mutation_chance)
|
171
202
|
.define_method("population_size=", &set_population_size)
|
172
|
-
.define_method("
|
203
|
+
.define_method("variants_count=", &set_variants_count)
|
204
|
+
.define_method("questions_count=", &set_questions_count)
|
173
205
|
.define_method("life_time", &get_life_time)
|
174
206
|
.define_method("mutation_chance", &get_mutation_chance)
|
175
207
|
.define_method("population_size", &get_population_size)
|
176
|
-
.define_method("
|
177
|
-
.define_method("
|
178
|
-
.define_method("
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
.define_method("
|
185
|
-
.define_method("
|
208
|
+
.define_method("variants_count", &get_variants_count)
|
209
|
+
.define_method("questions_count", &get_questions_count)
|
210
|
+
.define_method("topics", &get_topics)
|
211
|
+
.define_method("topics=", &set_topics);
|
212
|
+
|
213
|
+
Rice::Data_Type<topic_t> rb_ctopic = Rice::define_class_under<topic_t>(rb_mTasksGenerator, "Topic")
|
214
|
+
.define_constructor(Rice::Constructor<topic_t, size_t, size_t, std::string>(),
|
215
|
+
(Rice::Arg("id"), Rice::Arg("pid"), Rice::Arg("text")))
|
216
|
+
.define_method("topic_id", &topic_t::get_topic_id)
|
217
|
+
.define_method("parent_id", &topic_t::get_parent_id)
|
218
|
+
.define_method("text", &topic_t::get_text);
|
186
219
|
|
187
220
|
Rice::Data_Type<question_t> rb_cQuestion = Rice::define_class_under<question_t>(rb_mTasksGenerator, "Question")
|
188
|
-
.define_constructor(Rice::Constructor<question_t, size_t, size_t, size_t>(),
|
189
|
-
(Rice::Arg("id"), Rice::Arg("tid"), Rice::Arg("difficulty")))
|
221
|
+
.define_constructor(Rice::Constructor<question_t, size_t, size_t, size_t, std::string>(),
|
222
|
+
(Rice::Arg("id"), Rice::Arg("tid"), Rice::Arg("difficulty"), Rice::Arg("text")))
|
190
223
|
.define_method("question_id", &question_t::get_question_id)
|
191
|
-
.define_method("
|
192
|
-
.define_method("difficulty", &question_t::get_difficulty)
|
224
|
+
.define_method("topic_id", &question_t::get_topic_id)
|
225
|
+
.define_method("difficulty", &question_t::get_difficulty)
|
226
|
+
.define_method("text", &question_t::get_text);
|
193
227
|
|
194
228
|
Rice::Data_Type<generator_t> rb_cGenerator = Rice::define_class_under<generator_t>(rb_mTasksGenerator, "Generator")
|
195
|
-
.define_constructor(Rice::Constructor<generator_t, config_t, std::vector<question_t>>(),
|
196
|
-
(Rice::Arg("cnf"), Rice::Arg("questions")))
|
197
|
-
.define_method("config", &generator_t::get_config)
|
198
|
-
.define_method("questions", &generator_t::get_questions)
|
229
|
+
.define_constructor(Rice::Constructor<generator_t, config_t, std::vector<topic_t>, std::vector<question_t>>(),
|
230
|
+
(Rice::Arg("cnf"), Rice::Arg("topics"), Rice::Arg("questions")))
|
199
231
|
.define_method("generate", &generator_t::generate);
|
200
232
|
}
|
@@ -1,43 +1,79 @@
|
|
1
1
|
#pragma once
|
2
2
|
|
3
|
-
#include
|
4
|
-
#include
|
3
|
+
#include <iostream>
|
4
|
+
#include <unordered_map>
|
5
5
|
|
6
|
-
namespace
|
6
|
+
namespace ailab {
|
7
7
|
|
8
8
|
struct config_t {
|
9
9
|
size_t life_time;
|
10
|
-
|
10
|
+
size_t try_generate;
|
11
11
|
size_t population_size;
|
12
|
+
double mutation_chance;
|
13
|
+
double mutation_duplicate_chance;
|
14
|
+
bool log_enabled;
|
15
|
+
bool stat_enabled;
|
12
16
|
|
13
|
-
size_t
|
17
|
+
size_t variants_count;
|
18
|
+
size_t questions_count;
|
14
19
|
|
15
|
-
std::vector<
|
20
|
+
std::vector<size_t> topics;
|
16
21
|
|
17
|
-
config_t(
|
18
|
-
life_time(
|
19
|
-
|
20
|
-
population_size(
|
21
|
-
|
22
|
-
|
22
|
+
config_t(size_t v_count = 8, size_t q_count = 8) noexcept :
|
23
|
+
life_time(200),
|
24
|
+
try_generate(10),
|
25
|
+
population_size(100),
|
26
|
+
mutation_chance(0.01),
|
27
|
+
mutation_duplicate_chance(0.03),
|
28
|
+
log_enabled(false),
|
29
|
+
stat_enabled(false),
|
30
|
+
variants_count(v_count),
|
31
|
+
questions_count(q_count),
|
32
|
+
topics() {
|
23
33
|
}
|
24
34
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
35
|
+
config_t(std::unordered_map<std::string, std::string> const &map) noexcept :
|
36
|
+
config_t() {
|
37
|
+
if (map.find("life-time") != map.end())
|
38
|
+
life_time = std::stoul(map.at("life-time"));
|
39
|
+
if (map.find("population-size") != map.end())
|
40
|
+
population_size = std::stoul(map.at("population-size"));
|
41
|
+
if (map.find("mutation-chance") != map.end())
|
42
|
+
mutation_chance = std::stod(map.at("mutation-chance"));
|
43
|
+
if (map.find("log-enabled") != map.end())
|
44
|
+
log_enabled = true;
|
45
|
+
if (map.find("variants-count") != map.end())
|
46
|
+
variants_count = std::stoul(map.at("variants-count"));
|
47
|
+
if (map.find("questions-count") != map.end())
|
48
|
+
questions_count = std::stoul(map.at("questions-count"));
|
49
|
+
if (map.find("stat-enabled") != map.end())
|
50
|
+
stat_enabled = true;
|
51
|
+
if (map.find("mutation-duplicate-chance") != map.end())
|
52
|
+
mutation_duplicate_chance = std::stod(map.at("mutation-duplicate-chance"));
|
53
|
+
if (map.find("try-generate") != map.end())
|
54
|
+
try_generate = std::stod(map.at("try-generate"));
|
31
55
|
}
|
56
|
+
};
|
32
57
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
58
|
+
std::ostream& operator << (std::ostream& out, config_t const &config) {
|
59
|
+
out << "config.life_time = " << config.life_time << std::endl;
|
60
|
+
out << "config.population_size = " << config.population_size << std::endl;
|
61
|
+
out << "config.mutation_chance = " << config.mutation_chance << std::endl;
|
62
|
+
out << "config.mutation_duplicate_chance = " << config.mutation_duplicate_chance << std::endl;
|
63
|
+
out << "config.log_enabled = " << config.log_enabled << std::endl;
|
64
|
+
out << "config.stat_enabled = " << config.stat_enabled << std::endl;
|
65
|
+
out << "config.variants_count = " << config.variants_count << std::endl;
|
66
|
+
out << "config.questions_count = " << config.questions_count << std::endl;
|
67
|
+
out << "config.try_generate = " << config.try_generate << std::endl;
|
68
|
+
out << "config.topics = ";
|
69
|
+
for (size_t i = 0; i < config.topics.size(); ++i) {
|
70
|
+
out << config.topics[i];
|
71
|
+
if (i + 1 != config.topics.size())
|
72
|
+
out << ", ";
|
40
73
|
}
|
41
|
-
|
74
|
+
out << std::endl;
|
75
|
+
|
76
|
+
return out;
|
77
|
+
}
|
42
78
|
|
43
79
|
}
|
@@ -1,42 +1,185 @@
|
|
1
1
|
#pragma once
|
2
2
|
|
3
|
-
#include
|
3
|
+
#include <vector>
|
4
|
+
|
5
|
+
#include "config.h"
|
4
6
|
#include "question.h"
|
5
|
-
#include "
|
7
|
+
#include "question_shaker.h"
|
8
|
+
#include "topic.h"
|
9
|
+
#include "variants.h"
|
6
10
|
|
7
|
-
namespace
|
11
|
+
namespace ailab {
|
8
12
|
|
9
13
|
class generator_t {
|
14
|
+
struct stat_t {
|
15
|
+
size_t mutations_count;
|
16
|
+
size_t mutations_attempts;
|
17
|
+
size_t mutation_duplicate_count;
|
18
|
+
size_t mutation_duplicate_attempts;
|
19
|
+
size_t tried_generate;
|
20
|
+
double first_fitness_function;
|
21
|
+
double best_fitness_function;
|
22
|
+
|
23
|
+
stat_t() :
|
24
|
+
mutations_count(0),
|
25
|
+
mutations_attempts(0),
|
26
|
+
mutation_duplicate_count(0),
|
27
|
+
mutation_duplicate_attempts(0),
|
28
|
+
tried_generate(0),
|
29
|
+
first_fitness_function(0),
|
30
|
+
best_fitness_function(0) {
|
31
|
+
}
|
32
|
+
};
|
33
|
+
|
34
|
+
mutable stat_t stat;
|
35
|
+
|
10
36
|
config_t config;
|
37
|
+
std::vector<topic_t> topics;
|
11
38
|
std::vector<question_t> questions;
|
12
39
|
|
13
|
-
|
14
|
-
|
40
|
+
std::vector<variants_t> generate_population(question_shaker_t const &shaker) const {
|
41
|
+
std::vector<variants_t> result;
|
42
|
+
|
43
|
+
for (size_t k = 0; k < config.population_size; ++k) {
|
44
|
+
result.push_back(variants_t(config));
|
45
|
+
for (size_t i = 0; i < config.variants_count; ++i) {
|
46
|
+
for (size_t j = 0; j < config.questions_count; ++j) {
|
47
|
+
size_t r = rand() % config.topics.size();
|
48
|
+
result[k][i].push_back(shaker.get_question(config.topics[r]));
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
15
52
|
|
16
|
-
|
17
|
-
config(t.config),
|
18
|
-
questions(t.questions) {
|
53
|
+
return result;
|
19
54
|
}
|
20
55
|
|
21
|
-
|
22
|
-
|
23
|
-
|
56
|
+
void crossover(std::vector<variants_t> &population) const noexcept {
|
57
|
+
std::sort(population.begin(), population.end(), [] (variants_t const &a, variants_t const &b) -> bool {
|
58
|
+
return a.calculate_fitness_function() > b.calculate_fitness_function();
|
59
|
+
});
|
60
|
+
size_t population_size = population.size();
|
61
|
+
for (size_t i = 0; i + 1 < population_size; i += 2)
|
62
|
+
population.push_back(population[i].crossover(population[i + 1]));
|
63
|
+
for (size_t i = 0; i * 2 < population_size; ++i) {
|
64
|
+
size_t r = rand() % (population_size - i) + i;
|
65
|
+
population.push_back(population[i].crossover(population[r]));
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
void mutation(std::vector<variants_t> &population, question_shaker_t const &shaker) const {
|
70
|
+
size_t population_size = population.size();
|
71
|
+
for (size_t i = 0; i < population_size; ++i) {
|
72
|
+
bool b = (1 + rand() % 100) <= 100 * config.mutation_duplicate_chance;
|
73
|
+
++stat.mutation_duplicate_attempts;
|
74
|
+
if (b) {
|
75
|
+
population.push_back(population[i]);
|
76
|
+
++stat.mutation_duplicate_count;
|
77
|
+
}
|
78
|
+
for (size_t j = 0; j < population[i].size(); ++j)
|
79
|
+
for (size_t k = 0; k < population[i][j].size(); ++k) {
|
80
|
+
bool b = (1 + rand() % 100) <= 100 * config.mutation_chance;
|
81
|
+
++stat.mutations_attempts;
|
82
|
+
if (b) {
|
83
|
+
size_t r = rand() % config.topics.size();
|
84
|
+
population[i][j][k] = shaker.get_question(config.topics[r]);
|
85
|
+
++stat.mutations_count;
|
86
|
+
}
|
87
|
+
}
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
void selection(std::vector<variants_t> &population) const noexcept {
|
92
|
+
std::sort(population.begin(), population.end(), [] (variants_t const &a, variants_t const &b) -> bool {
|
93
|
+
return a.calculate_fitness_function() > b.calculate_fitness_function();
|
94
|
+
});
|
95
|
+
std::random_shuffle(population.begin() + config.population_size / 2, population.end());
|
96
|
+
population.resize(config.population_size + config.population_size / 2);
|
97
|
+
}
|
98
|
+
|
99
|
+
variants_t best(std::vector<variants_t> &population) const noexcept {
|
100
|
+
std::sort(population.begin(), population.end(), [] (variants_t const &a, variants_t const &b) -> bool {
|
101
|
+
return a.calculate_fitness_function() > b.calculate_fitness_function();
|
102
|
+
});
|
103
|
+
return population.front();
|
24
104
|
}
|
25
105
|
|
26
|
-
|
27
|
-
|
28
|
-
|
106
|
+
void strong_mutation(std::vector<variants_t> &population, question_shaker_t const &shaker) const noexcept {
|
107
|
+
for (variants_t &v : population)
|
108
|
+
v.strong_mutation(shaker);
|
29
109
|
}
|
30
110
|
|
31
|
-
|
32
|
-
|
111
|
+
bool good_result(variants_t const &v) const noexcept {
|
112
|
+
for (size_t i = 0; i < v.size(); ++i) {
|
113
|
+
std::unordered_set<size_t> counter;
|
114
|
+
for (size_t j = 0; j < v[i].size(); ++j)
|
115
|
+
counter.insert(v[i][j].get_question_id());
|
116
|
+
if (counter.size() < v[i].size())
|
117
|
+
return false;
|
118
|
+
}
|
119
|
+
return true;
|
33
120
|
}
|
34
121
|
|
35
|
-
|
36
|
-
|
122
|
+
public:
|
123
|
+
generator_t(config_t const &cnf, std::vector<topic_t> const &topics, std::vector<question_t> const &questions) noexcept :
|
124
|
+
config(cnf),
|
125
|
+
topics(topics),
|
126
|
+
questions(questions) {
|
127
|
+
}
|
128
|
+
|
129
|
+
generator_t(config_t &&cnf, std::vector<topic_t> &&topics, std::vector<question_t> &&questions) noexcept :
|
130
|
+
config(cnf),
|
131
|
+
topics(topics),
|
132
|
+
questions(questions) {
|
133
|
+
}
|
134
|
+
|
135
|
+
generator_t(generator_t const &other) noexcept :
|
136
|
+
config(other.config),
|
137
|
+
topics(other.topics),
|
138
|
+
questions(other.questions) {
|
37
139
|
}
|
38
140
|
|
39
|
-
|
141
|
+
variants_t generate() {
|
142
|
+
++stat.tried_generate;
|
143
|
+
|
144
|
+
question_shaker_t shaker(topics, questions);
|
145
|
+
std::vector<variants_t> population = generate_population(shaker);
|
146
|
+
|
147
|
+
variants_t result = best(population);
|
148
|
+
stat.best_fitness_function = stat.first_fitness_function = result.calculate_fitness_function();
|
149
|
+
|
150
|
+
for (size_t current_time = 1; current_time <= config.life_time; ++current_time) {
|
151
|
+
crossover(population);
|
152
|
+
selection(population);
|
153
|
+
mutation(population, shaker);
|
154
|
+
strong_mutation(population, shaker);
|
155
|
+
|
156
|
+
if (config.log_enabled)
|
157
|
+
std::cerr << current_time << '\t' << result.calculate_fitness_function() << std::endl;
|
158
|
+
|
159
|
+
variants_t buf = best(population);
|
160
|
+
if (buf.calculate_fitness_function() > result.calculate_fitness_function()) {
|
161
|
+
result = buf;
|
162
|
+
stat.best_fitness_function = result.calculate_fitness_function();
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
if (good_result(result) || stat.tried_generate == config.try_generate) {
|
167
|
+
if (config.stat_enabled) {
|
168
|
+
std::cerr << std::endl;
|
169
|
+
std::cerr << "stat.tried_generate = " << stat.tried_generate << std::endl;
|
170
|
+
std::cerr << "stat.mutations_attempts = " << stat.mutations_attempts << std::endl;
|
171
|
+
std::cerr << "stat.mutations_count = " << stat.mutations_count << std::endl;
|
172
|
+
std::cerr << "stat.mutation_duplicate_attempts = " << stat.mutation_duplicate_attempts << std::endl;
|
173
|
+
std::cerr << "stat.mutation_duplicate_count = " << stat.mutation_duplicate_count << std::endl;
|
174
|
+
std::cerr << "stat.first_fitness_function = " << stat.first_fitness_function << std::endl;
|
175
|
+
std::cerr << "stat.best_fitness_function = " << stat.best_fitness_function << std::endl;
|
176
|
+
std::cerr << std::endl;
|
177
|
+
}
|
178
|
+
return result;
|
179
|
+
} else {
|
180
|
+
return generate();
|
181
|
+
}
|
182
|
+
}
|
40
183
|
};
|
41
184
|
|
42
185
|
}
|
@@ -2,50 +2,42 @@
|
|
2
2
|
|
3
3
|
#include <string>
|
4
4
|
|
5
|
-
namespace
|
5
|
+
namespace ailab {
|
6
6
|
|
7
7
|
class question_t {
|
8
|
-
size_t question_id,
|
8
|
+
size_t question_id, topic_id, difficulty, select_id;
|
9
|
+
std::string text;
|
9
10
|
|
10
|
-
public:
|
11
|
-
question_t() :
|
12
|
-
question_id(
|
13
|
-
|
14
|
-
difficulty(
|
11
|
+
public:
|
12
|
+
question_t(size_t question_id, size_t topic_id, size_t difficulty, std::string const text = "") noexcept :
|
13
|
+
question_id(question_id),
|
14
|
+
topic_id(topic_id),
|
15
|
+
difficulty(difficulty),
|
16
|
+
text(text) {
|
15
17
|
}
|
16
18
|
|
17
|
-
|
18
|
-
|
19
|
-
theme_id(tid),
|
20
|
-
difficulty(difficulty) {
|
19
|
+
void set_select_id(size_t x) noexcept {
|
20
|
+
select_id = x;
|
21
21
|
}
|
22
22
|
|
23
|
-
size_t
|
24
|
-
return
|
23
|
+
size_t get_select_id() const noexcept {
|
24
|
+
return select_id;
|
25
25
|
}
|
26
26
|
|
27
|
-
size_t get_question_id() const {
|
27
|
+
size_t get_question_id() const noexcept {
|
28
28
|
return question_id;
|
29
29
|
}
|
30
30
|
|
31
|
-
size_t
|
32
|
-
return
|
33
|
-
}
|
34
|
-
|
35
|
-
bool operator == (question_t const &q) const {
|
36
|
-
return question_id == q.question_id;
|
31
|
+
size_t get_topic_id() const noexcept {
|
32
|
+
return topic_id;
|
37
33
|
}
|
38
34
|
|
39
|
-
|
40
|
-
return
|
41
|
-
}
|
42
|
-
|
43
|
-
static bool difficulty_cmp(question_t const &a, question_t const &b) {
|
44
|
-
return a.difficulty < b.difficulty;
|
35
|
+
size_t get_difficulty() const noexcept {
|
36
|
+
return difficulty;
|
45
37
|
}
|
46
38
|
|
47
|
-
|
48
|
-
return
|
39
|
+
std::string const &get_text() const noexcept {
|
40
|
+
return text;
|
49
41
|
}
|
50
42
|
};
|
51
43
|
|
@@ -0,0 +1,62 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <algorithm>
|
4
|
+
#include <cstdlib>
|
5
|
+
#include <unordered_map>
|
6
|
+
#include <unordered_set>
|
7
|
+
#include <vector>
|
8
|
+
|
9
|
+
#include "topic.h"
|
10
|
+
#include "question.h"
|
11
|
+
|
12
|
+
namespace ailab {
|
13
|
+
|
14
|
+
// TODO: make it without O(n^2) size
|
15
|
+
class question_shaker_t {
|
16
|
+
std::unordered_map<size_t, topic_t> topics;
|
17
|
+
std::unordered_map<size_t, std::vector<question_t>> questions;
|
18
|
+
|
19
|
+
void dfs(size_t u, std::unordered_map<size_t, std::vector<size_t>> const &g, std::unordered_set<size_t> &used) noexcept {
|
20
|
+
used.insert(u);
|
21
|
+
if (g.find(u) == g.end())
|
22
|
+
return;
|
23
|
+
for (size_t i = 0; i < g.at(u).size(); ++i) {
|
24
|
+
size_t v = g.at(u)[i];
|
25
|
+
if (used.find(v) == used.end()) {
|
26
|
+
dfs(v, g, used);
|
27
|
+
for (question_t const &q : questions[v])
|
28
|
+
questions[u].push_back(q);
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
public:
|
34
|
+
question_shaker_t(std::vector<topic_t> const &t, std::vector<question_t> const &q) noexcept {
|
35
|
+
for (question_t const &question : q)
|
36
|
+
questions[question.get_topic_id()].push_back(question);
|
37
|
+
for (topic_t const &topic : t)
|
38
|
+
topics[topic.get_topic_id()] = topic;
|
39
|
+
std::unordered_map<size_t, std::vector<size_t>> g;
|
40
|
+
std::unordered_set<size_t> used;
|
41
|
+
for (topic_t const &topic : t)
|
42
|
+
if (topic.get_parent_id() != 0)
|
43
|
+
g[topic.get_parent_id()].push_back(topic.get_topic_id());
|
44
|
+
for (topic_t const &topic : t)
|
45
|
+
if (used.find(topic.get_topic_id()) == used.end())
|
46
|
+
dfs(topic.get_topic_id(), g, used);
|
47
|
+
for (auto &p : questions)
|
48
|
+
std::random_shuffle(p.second.begin(), p.second.end());
|
49
|
+
srand(time(0));
|
50
|
+
}
|
51
|
+
|
52
|
+
question_t get_question(size_t topic_id) const {
|
53
|
+
if (questions.at(topic_id).empty())
|
54
|
+
throw std::logic_error("Not enough questions for topic");
|
55
|
+
size_t r = rand() % questions.at(topic_id).size();
|
56
|
+
question_t result = questions.at(topic_id)[r];
|
57
|
+
result.set_select_id(topic_id);
|
58
|
+
return result;
|
59
|
+
}
|
60
|
+
};
|
61
|
+
|
62
|
+
}
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <string>
|
4
|
+
|
5
|
+
namespace ailab {
|
6
|
+
|
7
|
+
class topic_t {
|
8
|
+
size_t topic_id, parent_id;
|
9
|
+
std::string text;
|
10
|
+
|
11
|
+
public:
|
12
|
+
topic_t(size_t topic_id = 0, size_t parent_id = 0, std::string const &text = "") noexcept :
|
13
|
+
topic_id(topic_id),
|
14
|
+
parent_id(parent_id),
|
15
|
+
text(text) {
|
16
|
+
}
|
17
|
+
|
18
|
+
size_t get_topic_id() const noexcept {
|
19
|
+
return topic_id;
|
20
|
+
}
|
21
|
+
|
22
|
+
size_t get_parent_id() const noexcept {
|
23
|
+
return parent_id;
|
24
|
+
}
|
25
|
+
|
26
|
+
std::string const &get_text() const noexcept {
|
27
|
+
return text;
|
28
|
+
}
|
29
|
+
};
|
30
|
+
|
31
|
+
}
|
@@ -0,0 +1,200 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <vector>
|
4
|
+
|
5
|
+
#include "question.h"
|
6
|
+
|
7
|
+
namespace ailab {
|
8
|
+
|
9
|
+
class variants_t {
|
10
|
+
mutable double fitness;
|
11
|
+
mutable bool changed;
|
12
|
+
|
13
|
+
config_t const &config;
|
14
|
+
|
15
|
+
size_t questions_count;
|
16
|
+
std::vector<std::vector<question_t>> questions;
|
17
|
+
|
18
|
+
public:
|
19
|
+
variants_t(config_t const &config = config_t()) noexcept :
|
20
|
+
fitness(0),
|
21
|
+
changed(true),
|
22
|
+
config(config),
|
23
|
+
questions(config.variants_count) {
|
24
|
+
}
|
25
|
+
|
26
|
+
variants_t(variants_t const &v) noexcept :
|
27
|
+
fitness(v.fitness),
|
28
|
+
changed(v.changed),
|
29
|
+
config(v.config),
|
30
|
+
questions(v.questions) {
|
31
|
+
}
|
32
|
+
|
33
|
+
variants_t(variants_t &&v) noexcept :
|
34
|
+
config(v.config) {
|
35
|
+
std::swap(fitness, v.fitness);
|
36
|
+
std::swap(changed, v.changed);
|
37
|
+
std::swap(questions, v.questions);
|
38
|
+
}
|
39
|
+
|
40
|
+
variants_t &operator = (variants_t &&v) noexcept {
|
41
|
+
std::swap(fitness, v.fitness);
|
42
|
+
std::swap(changed, v.changed);
|
43
|
+
std::swap(questions, v.questions);
|
44
|
+
|
45
|
+
return *this;
|
46
|
+
}
|
47
|
+
|
48
|
+
variants_t &operator = (variants_t const &v) noexcept {
|
49
|
+
fitness = v.fitness;
|
50
|
+
changed = v.changed;
|
51
|
+
questions = v.questions;
|
52
|
+
|
53
|
+
return *this;
|
54
|
+
}
|
55
|
+
|
56
|
+
void push_back(std::vector<question_t> const &q) noexcept {
|
57
|
+
questions.push_back(q);
|
58
|
+
}
|
59
|
+
|
60
|
+
size_t size() const noexcept {
|
61
|
+
return questions.size();
|
62
|
+
}
|
63
|
+
|
64
|
+
std::vector<std::vector<question_t>>::iterator begin() noexcept {
|
65
|
+
return questions.begin();
|
66
|
+
}
|
67
|
+
|
68
|
+
std::vector<std::vector<question_t>>::iterator end() noexcept {
|
69
|
+
return questions.end();
|
70
|
+
}
|
71
|
+
|
72
|
+
double calculate_fitness_function() const noexcept {
|
73
|
+
if (!changed)
|
74
|
+
return fitness;
|
75
|
+
size_t questions_count = 0;
|
76
|
+
for (auto const &v : questions)
|
77
|
+
questions_count += v.size();
|
78
|
+
{
|
79
|
+
size_t buffer[questions_count];
|
80
|
+
for (size_t i = 0; i < questions.size(); ++i)
|
81
|
+
for (size_t j = 0; j < questions[i].size(); ++j)
|
82
|
+
buffer[i * config.questions_count + j] = questions[i][j].get_question_id();
|
83
|
+
std::sort(buffer, buffer + questions_count);
|
84
|
+
size_t count = 1;
|
85
|
+
for (size_t i = 1; i < questions_count; ++i)
|
86
|
+
count += buffer[i] != buffer[i - 1];
|
87
|
+
fitness = double(count) / questions_count;
|
88
|
+
}
|
89
|
+
{
|
90
|
+
for (size_t i = 0; i < questions.size(); ++i) {
|
91
|
+
size_t buffer[questions[i].size()];
|
92
|
+
for (size_t j = 0; j < questions[i].size(); ++j)
|
93
|
+
buffer[j] = questions[i][j].get_question_id();
|
94
|
+
std::sort(buffer, buffer + questions[i].size());
|
95
|
+
size_t count = 1;
|
96
|
+
for (size_t j = 1; j < questions[i].size(); ++j)
|
97
|
+
count += buffer[j] != buffer[j - 1];
|
98
|
+
fitness += count == questions[i].size();
|
99
|
+
}
|
100
|
+
}
|
101
|
+
{
|
102
|
+
for (size_t i = 0; i < questions.size(); ++i) {
|
103
|
+
size_t buffer[questions[i].size()];
|
104
|
+
for (size_t j = 0; j < questions[i].size(); ++j)
|
105
|
+
buffer[j] = questions[i][j].get_select_id();
|
106
|
+
std::sort(buffer, buffer + questions[i].size());
|
107
|
+
size_t count = 1;
|
108
|
+
for (size_t j = 1; j < questions[i].size(); ++j)
|
109
|
+
count += buffer[j] != buffer[j - 1];
|
110
|
+
fitness += double(count) / questions[i].size();
|
111
|
+
}
|
112
|
+
}
|
113
|
+
{
|
114
|
+
double buffer[questions_count];
|
115
|
+
for (size_t i = 0; i < questions.size(); ++i)
|
116
|
+
for (size_t j = 0; j < questions[i].size(); ++j)
|
117
|
+
buffer[i * config.questions_count + j] = questions[i][j].get_difficulty();
|
118
|
+
double avg = 0;
|
119
|
+
for (size_t i = 0; i < questions_count; ++i)
|
120
|
+
avg += buffer[i];
|
121
|
+
avg /= questions_count;
|
122
|
+
double x = 0;
|
123
|
+
for (size_t i = 0; i < questions_count; ++i)
|
124
|
+
x += (buffer[i] - avg) * (buffer[i] - avg);
|
125
|
+
x /= questions_count;
|
126
|
+
x = sqrt(x);
|
127
|
+
fitness += x;
|
128
|
+
}
|
129
|
+
{
|
130
|
+
for (size_t i = 0; i < questions.size(); ++i) {
|
131
|
+
size_t buffer[questions[i].size()];
|
132
|
+
for (size_t j = 0; j < questions[i].size(); ++j)
|
133
|
+
buffer[j] = questions[i][j].get_select_id();
|
134
|
+
std::sort(buffer, buffer + questions[i].size());
|
135
|
+
size_t count = 1;
|
136
|
+
for (size_t j = 1; j < questions[i].size(); ++j)
|
137
|
+
count += buffer[j] != buffer[j - 1];
|
138
|
+
std::pair<size_t, size_t> counter[count];
|
139
|
+
ssize_t k = -1;
|
140
|
+
for (size_t j = 0; j < questions[i].size(); ++j) {
|
141
|
+
if (k == -1 || buffer[j] != counter[k].first) {
|
142
|
+
++k;
|
143
|
+
counter[k].second = 0;
|
144
|
+
}
|
145
|
+
++counter[k].second;
|
146
|
+
}
|
147
|
+
std::sort(counter, counter + count, [] (std::pair<size_t, size_t> const &a, std::pair<size_t, size_t> const &b) -> bool {
|
148
|
+
return a.second > b.second;
|
149
|
+
});
|
150
|
+
double x = 0;
|
151
|
+
for (size_t j = 1; j < count; ++j)
|
152
|
+
x += counter[j].second / counter[j - 1].second;
|
153
|
+
fitness += x;
|
154
|
+
}
|
155
|
+
}
|
156
|
+
changed = false;
|
157
|
+
return fitness;
|
158
|
+
}
|
159
|
+
|
160
|
+
variants_t crossover(variants_t const &v) const noexcept {
|
161
|
+
variants_t result(*this);
|
162
|
+
size_t questions_count = 0;
|
163
|
+
for (auto const &v : questions)
|
164
|
+
questions_count += v.size();
|
165
|
+
size_t to_swap = rand() % questions_count;
|
166
|
+
for (size_t i = 0; i < result.questions.size() && to_swap; ++i)
|
167
|
+
for (size_t j = 0; j < result.questions[i].size() && to_swap; ++j, --to_swap)
|
168
|
+
result.questions[i][j] = v.questions[i][j];
|
169
|
+
return result;
|
170
|
+
}
|
171
|
+
|
172
|
+
std::vector<question_t> &operator [] (size_t i) noexcept {
|
173
|
+
changed = true;
|
174
|
+
return questions[i];
|
175
|
+
}
|
176
|
+
|
177
|
+
std::vector<question_t> const &operator [] (size_t i) const noexcept {
|
178
|
+
return questions[i];
|
179
|
+
}
|
180
|
+
|
181
|
+
void strong_mutation(question_shaker_t const &shaker) noexcept {
|
182
|
+
for (std::vector<question_t> &q : *this) {
|
183
|
+
std::sort(q.begin(), q.end(), [] (question_t const &a, question_t const &b) -> bool {
|
184
|
+
return a.get_question_id() < b.get_question_id();
|
185
|
+
});
|
186
|
+
for (size_t i = 1; i < q.size(); ++i) {
|
187
|
+
if (q[i].get_question_id() == q[i - 1].get_question_id()) {
|
188
|
+
size_t r = rand() % config.topics.size();
|
189
|
+
q[i - 1] = shaker.get_question(config.topics[r]);
|
190
|
+
}
|
191
|
+
}
|
192
|
+
}
|
193
|
+
}
|
194
|
+
|
195
|
+
std::vector<std::vector<question_t>> const &get_questions() const noexcept {
|
196
|
+
return questions;
|
197
|
+
}
|
198
|
+
};
|
199
|
+
|
200
|
+
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tasks_generator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0
|
4
|
+
version: '1.0'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arslan Urtashev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -28,28 +28,28 @@ dependencies:
|
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - '>='
|
31
|
+
- - ! '>='
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - '>='
|
38
|
+
- - ! '>='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rice
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - '>='
|
45
|
+
- - ! '>='
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - '>='
|
52
|
+
- - ! '>='
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
description: Test Tasks Generator for AI lab MEPhI
|
@@ -67,13 +67,11 @@ files:
|
|
67
67
|
- ext/tasks_generator/bindings.cc
|
68
68
|
- ext/tasks_generator/config.h
|
69
69
|
- ext/tasks_generator/extconf.rb
|
70
|
-
- ext/tasks_generator/function.cc
|
71
|
-
- ext/tasks_generator/function.h
|
72
|
-
- ext/tasks_generator/generator.cc
|
73
70
|
- ext/tasks_generator/generator.h
|
74
71
|
- ext/tasks_generator/question.h
|
75
|
-
- ext/tasks_generator/
|
76
|
-
- ext/tasks_generator/
|
72
|
+
- ext/tasks_generator/question_shaker.h
|
73
|
+
- ext/tasks_generator/topic.h
|
74
|
+
- ext/tasks_generator/variants.h
|
77
75
|
- lib/tasks_generator.rb
|
78
76
|
- lib/tasks_generator/version.rb
|
79
77
|
- tasks_generator.gemspec
|
@@ -87,17 +85,17 @@ require_paths:
|
|
87
85
|
- lib
|
88
86
|
required_ruby_version: !ruby/object:Gem::Requirement
|
89
87
|
requirements:
|
90
|
-
- - '>='
|
88
|
+
- - ! '>='
|
91
89
|
- !ruby/object:Gem::Version
|
92
90
|
version: '0'
|
93
91
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
92
|
requirements:
|
95
|
-
- - '>='
|
93
|
+
- - ! '>='
|
96
94
|
- !ruby/object:Gem::Version
|
97
95
|
version: '0'
|
98
96
|
requirements: []
|
99
97
|
rubyforge_project:
|
100
|
-
rubygems_version: 2.
|
98
|
+
rubygems_version: 2.4.4
|
101
99
|
signing_key:
|
102
100
|
specification_version: 4
|
103
101
|
summary: Test Tasks Generator
|
@@ -1,147 +0,0 @@
|
|
1
|
-
#include <algorithm>
|
2
|
-
#include <unordered_map>
|
3
|
-
#include <unordered_set>
|
4
|
-
#include <vector>
|
5
|
-
|
6
|
-
#include <cassert>
|
7
|
-
#include <cstdlib>
|
8
|
-
|
9
|
-
#include "function.h"
|
10
|
-
#include "question.h"
|
11
|
-
|
12
|
-
namespace tasks_generator {
|
13
|
-
|
14
|
-
population_t generate_population(config_t const &config, std::vector<question_t> const &questions) {
|
15
|
-
|
16
|
-
std::unordered_map<theme_id_t, std::vector<question_t>> all_questions;
|
17
|
-
for (question_t const &question : questions)
|
18
|
-
all_questions[question.get_theme_id()].push_back(question);
|
19
|
-
for (std::pair<theme_id_t const, std::vector<question_t>> &q : all_questions)
|
20
|
-
std::sort(q.second.begin(), q.second.end(), question_t::difficulty_cmp);
|
21
|
-
|
22
|
-
population_t population(config.population_size);
|
23
|
-
|
24
|
-
srand((unsigned int)time(0));
|
25
|
-
|
26
|
-
for (individual_t &individual : population) {
|
27
|
-
individual = individual_t(config.tasks, task_t(config.themes.size()));
|
28
|
-
|
29
|
-
for (task_t &task : individual) {
|
30
|
-
task = task_t(config.themes.size());
|
31
|
-
|
32
|
-
std::unordered_set<question_id_t> used;
|
33
|
-
|
34
|
-
for (size_t i = 0; i < task.size(); ++i) {
|
35
|
-
std::vector<question_t> const &candidates = all_questions[config.themes[i].get_theme_id()];
|
36
|
-
|
37
|
-
std::vector<question_t>::const_iterator lower = std::lower_bound(
|
38
|
-
candidates.begin(),
|
39
|
-
candidates.end(),
|
40
|
-
config.themes[i].get_difficulty_min(),
|
41
|
-
question_t::difficulty_size_t_cmp
|
42
|
-
);
|
43
|
-
|
44
|
-
size_t unused_count = 0;
|
45
|
-
std::vector<question_t>::const_iterator it = lower;
|
46
|
-
while (it != candidates.end() && it->get_difficulty() <= config.themes[i].get_difficulty_max()) {
|
47
|
-
if (used.find(it->get_question_id()) == used.end())
|
48
|
-
++unused_count;
|
49
|
-
++it;
|
50
|
-
}
|
51
|
-
|
52
|
-
if (unused_count == 0)
|
53
|
-
throw std::logic_error("hasn't questions for generate test");
|
54
|
-
|
55
|
-
size_t pos = rand() % unused_count;
|
56
|
-
|
57
|
-
it = lower;
|
58
|
-
while (pos > 0 || used.find(it->get_question_id()) != used.end()) {
|
59
|
-
if (used.find(it->get_question_id()) == used.end())
|
60
|
-
--pos;
|
61
|
-
++it;
|
62
|
-
}
|
63
|
-
|
64
|
-
task[i] = *it;
|
65
|
-
used.insert(it->get_question_id());
|
66
|
-
}
|
67
|
-
}
|
68
|
-
}
|
69
|
-
|
70
|
-
return population;
|
71
|
-
}
|
72
|
-
|
73
|
-
static double fitness(individual_t const &individual) {
|
74
|
-
double s = 0, sqrs = 0;
|
75
|
-
for (task_t const &task : individual) {
|
76
|
-
double avg = 0;
|
77
|
-
for (question_t const &question : task)
|
78
|
-
avg += question.get_difficulty();
|
79
|
-
avg /= task.size();
|
80
|
-
s += avg;
|
81
|
-
sqrs += avg * avg;
|
82
|
-
}
|
83
|
-
double d = (sqrs - s * s / individual.size()) / individual.size();
|
84
|
-
double metric_one = (d > 0 ? 1.0 / d + 1.0 : 2);
|
85
|
-
|
86
|
-
std::unordered_set<size_t> uniqs;
|
87
|
-
for (task_t const &task : individual)
|
88
|
-
for (question_t const &question : task)
|
89
|
-
uniqs.insert(question.get_question_id());
|
90
|
-
|
91
|
-
return metric_one * uniqs.size(); // FIXME: add diff metric
|
92
|
-
}
|
93
|
-
|
94
|
-
static individual_t crossover(individual_t const &a, individual_t const &b) {
|
95
|
-
// FIXME: change this crossover
|
96
|
-
assert(a.size() == b.size());
|
97
|
-
individual_t res;
|
98
|
-
size_t to = rand() % a.size();
|
99
|
-
for (size_t i = 0; i < to; ++i)
|
100
|
-
res.push_back(a[i]);
|
101
|
-
for (size_t i = to; i < b.size(); ++i)
|
102
|
-
res.push_back(b[i]);
|
103
|
-
return res;
|
104
|
-
}
|
105
|
-
|
106
|
-
static void sort_by_fitness(population_t &population) {
|
107
|
-
std::vector<std::pair<double, size_t>> buf(population.size());
|
108
|
-
for (size_t i = 0; i < population.size(); ++i) {
|
109
|
-
buf[i].first = fitness(population[i]);
|
110
|
-
buf[i].second = i;
|
111
|
-
}
|
112
|
-
std::sort(buf.begin(), buf.end());
|
113
|
-
for (size_t i = 0; i < population.size(); ++i)
|
114
|
-
std::swap(population[i], population[buf[i].second]);
|
115
|
-
}
|
116
|
-
|
117
|
-
individual_t best(population_t &population) {
|
118
|
-
assert(!population.empty());
|
119
|
-
sort_by_fitness(population);
|
120
|
-
return population.front();
|
121
|
-
}
|
122
|
-
|
123
|
-
void selection(config_t const &config, population_t &population) {
|
124
|
-
// FIXME: make selection better
|
125
|
-
sort_by_fitness(population);
|
126
|
-
population.resize(config.population_size);
|
127
|
-
}
|
128
|
-
|
129
|
-
void recombination(config_t const &config, population_t &population) {
|
130
|
-
if (population.empty())
|
131
|
-
throw std::logic_error("population is empty");
|
132
|
-
std::vector<individual_t> newbies;
|
133
|
-
for (size_t i = 0; i < population.size(); ++i) {
|
134
|
-
size_t pos = i + rand() % (population.size() - i);
|
135
|
-
std::swap(population[i], population[pos]);
|
136
|
-
}
|
137
|
-
for (size_t i = 0; i < population.size(); i += 2) {
|
138
|
-
newbies.push_back(crossover(population[i], population[i + 1]));
|
139
|
-
}
|
140
|
-
for (size_t i = 0; i < newbies.size(); ++i)
|
141
|
-
population.emplace_back(std::move(newbies[i]));
|
142
|
-
}
|
143
|
-
|
144
|
-
void mutation(config_t const &, population_t &) {
|
145
|
-
}
|
146
|
-
|
147
|
-
}
|
@@ -1,22 +0,0 @@
|
|
1
|
-
#pragma once
|
2
|
-
|
3
|
-
#include <algorithm>
|
4
|
-
#include <vector>
|
5
|
-
|
6
|
-
#include "config.h"
|
7
|
-
#include "question.h"
|
8
|
-
#include "types.h"
|
9
|
-
|
10
|
-
namespace tasks_generator {
|
11
|
-
|
12
|
-
population_t generate_population(config_t const &config, std::vector<question_t> const &questions);
|
13
|
-
|
14
|
-
individual_t best(population_t &population);
|
15
|
-
|
16
|
-
void selection(config_t const &config, population_t &population);
|
17
|
-
|
18
|
-
void recombination(config_t const &config, population_t &population);
|
19
|
-
|
20
|
-
void mutation(config_t const &config, population_t &population);
|
21
|
-
|
22
|
-
}
|
@@ -1,23 +0,0 @@
|
|
1
|
-
#include <vector>
|
2
|
-
|
3
|
-
#include "generator.h"
|
4
|
-
|
5
|
-
#include "function.h"
|
6
|
-
#include "question.h"
|
7
|
-
#include "types.h"
|
8
|
-
|
9
|
-
namespace tasks_generator {
|
10
|
-
|
11
|
-
generator_t::answer_t generator_t::generate() const {
|
12
|
-
population_t population = generate_population(config, questions);
|
13
|
-
|
14
|
-
for (size_t current_time = 0; current_time < config.life_time; ++current_time) {
|
15
|
-
selection(config, population);
|
16
|
-
recombination(config, population);
|
17
|
-
mutation(config, population);
|
18
|
-
}
|
19
|
-
|
20
|
-
return best(population);
|
21
|
-
}
|
22
|
-
|
23
|
-
}
|
data/ext/tasks_generator/theme.h
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
#pragma once
|
2
|
-
|
3
|
-
#include "question.h"
|
4
|
-
|
5
|
-
namespace tasks_generator {
|
6
|
-
|
7
|
-
class theme_t {
|
8
|
-
size_t theme_id, difficulty_min, difficulty_max;
|
9
|
-
|
10
|
-
public:
|
11
|
-
theme_t(size_t tid, size_t dmin, size_t dmax) :
|
12
|
-
theme_id(tid),
|
13
|
-
difficulty_min(dmin),
|
14
|
-
difficulty_max(dmax) {
|
15
|
-
}
|
16
|
-
|
17
|
-
theme_t(theme_t const &th) :
|
18
|
-
theme_id(th.theme_id),
|
19
|
-
difficulty_min(th.difficulty_min),
|
20
|
-
difficulty_max(th.difficulty_max) {
|
21
|
-
}
|
22
|
-
|
23
|
-
size_t get_theme_id() const {
|
24
|
-
return theme_id;
|
25
|
-
}
|
26
|
-
|
27
|
-
size_t get_difficulty_min() const {
|
28
|
-
return difficulty_min;
|
29
|
-
}
|
30
|
-
|
31
|
-
size_t get_difficulty_max() const {
|
32
|
-
return difficulty_max;
|
33
|
-
}
|
34
|
-
|
35
|
-
bool operator == (theme_t const &t) const {
|
36
|
-
return theme_id == t.theme_id &&
|
37
|
-
difficulty_min == t.difficulty_min &&
|
38
|
-
difficulty_max == t.difficulty_max;
|
39
|
-
}
|
40
|
-
};
|
41
|
-
|
42
|
-
}
|
data/ext/tasks_generator/types.h
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
#pragma once
|
2
|
-
|
3
|
-
#include <vector>
|
4
|
-
|
5
|
-
#include "question.h"
|
6
|
-
|
7
|
-
#define __unsed __attribute__((unused))
|
8
|
-
|
9
|
-
namespace tasks_generator {
|
10
|
-
|
11
|
-
typedef std::vector<question_t> task_t;
|
12
|
-
typedef std::vector<task_t> individual_t;
|
13
|
-
typedef std::vector<individual_t> population_t;
|
14
|
-
|
15
|
-
typedef size_t theme_id_t;
|
16
|
-
typedef size_t question_id_t;
|
17
|
-
|
18
|
-
}
|