tasks_generator 0.5 → 1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
-
}
|