Skip to content

Commit 8e3724a

Browse files
committed
change to Nutrient DoTaskInteraction and tests for new task refactors
1 parent 7ed822e commit 8e3724a

2 files changed

Lines changed: 231 additions & 1 deletion

File tree

source/sgp_mode/SGPSymbiont.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ class SGPSymbiont : public Symbiont {
136136
double to_steal = sgp_config->NUTRIENT_DONATE_STEAL_PROP() * score;
137137
double from_host = emp::Min(my_host->GetPoints(), to_steal); //parasite only can steal what's available
138138
my_host->AddPoints(-from_host);
139-
score = from_host;
139+
score += from_host;
140140
}
141141
else if (is_parasite == 0 && host_performed) { //Mutualist
142142
double to_donate = sgp_config->NUTRIENT_DONATE_STEAL_PROP() * score;

source/test/sgp_mode_test/tasks.test.cc

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,234 @@ TEST_CASE("When only first task credit is on","[ony]"){
5151
}
5252
}
5353
}
54+
}
55+
//TODO: tasks -> Tasks for folder name and test name (Task.integration.test.cc)
56+
// MOVE program builder outside of WHEN to cut down replications
57+
// Move CPU cycles from THEN to WHEN
58+
TEST_CASE("Task completion scoring and marking", "[tasks]") {
59+
emp::Random random(1);
60+
SymConfigSGP config;
61+
config.SEED(1);
62+
config.MUTATION_RATE(0.0);
63+
config.MUTATION_SIZE(0.002);
64+
config.TRACK_PARENT_TASKS(1);
65+
config.VT_TASK_MATCH(1);
66+
67+
WHEN("OnlyFirstTaskCredit is OFF") {
68+
config.ONLY_FIRST_TASK_CREDIT(0);
69+
SGPWorld world(random, &config, LogicTasks);
70+
71+
// multiple tasks
72+
ProgramBuilder multi_task_program;
73+
multi_task_program.AddNot();
74+
multi_task_program.AddNand();
75+
multi_task_program.AddAnd();
76+
77+
emp::Ptr<SGPHost> host = emp::NewPtr<SGPHost>(&random, &world, &config, multi_task_program.Build(100));
78+
world.AddOrgAt(host, 0);
79+
80+
THEN("Should receive score when task completed") {
81+
int initial_points = host->GetPoints();
82+
host->GetCPU().RunCPUStep(0, 100);
83+
84+
// Get points for alltasks
85+
REQUIRE(host->GetPoints() > initial_points);
86+
}
87+
88+
THEN("Should mark task when task completed") {
89+
host->GetCPU().RunCPUStep(0, 100);
90+
91+
// Check that tasks marked complete
92+
int tasks_completed = 0;
93+
for (int i = 0; i < CPU_BITSET_LENGTH; i++) {
94+
tasks_completed += host->GetCPU().state.tasks_performed->Get(i);
95+
}
96+
REQUIRE(tasks_completed > 0);
97+
}
98+
}
99+
100+
WHEN("OnlyFirstTaskCredit is ON") {
101+
config.ONLY_FIRST_TASK_CREDIT(1);
102+
SGPWorld world(random, &config, LogicTasks);
103+
104+
// Program with multiple tasks
105+
ProgramBuilder multi_task_program;
106+
multi_task_program.AddNot();
107+
multi_task_program.AddNand();
108+
multi_task_program.AddAnd();
109+
110+
emp::Ptr<SGPHost> host = emp::NewPtr<SGPHost>(&random, &world, &config, multi_task_program.Build(100));
111+
world.AddOrgAt(host, 0);
112+
113+
THEN("Should receive score when task completed if it is first task") {
114+
int initial_points = host->GetPoints();
115+
host->GetCPU().RunCPUStep(0, 100);
116+
117+
// Points for first task only
118+
REQUIRE(host->GetPoints() == initial_points + 5);
119+
}
120+
121+
THEN("Should not receive score when task completed if it is not first task") {
122+
// First for first task
123+
host->GetCPU().RunCPUStep(0, 100);
124+
int points_after_first = host->GetPoints(); //change points after task --> 10
125+
126+
// Second run (should not get points)
127+
host->GetCPU().RunCPUStep(0, 100);
128+
REQUIRE(host->GetPoints() == points_after_first);
129+
}
130+
131+
THEN("Should mark task completed when it is first task") {
132+
host->GetCPU().RunCPUStep(0, 100);
133+
134+
// exactly one task is marked complete
135+
int tasks_completed = 0;
136+
for (int i = 0; i < CPU_BITSET_LENGTH; i++) {
137+
tasks_completed += host->GetCPU().state.tasks_performed->Get(i);
138+
}
139+
REQUIRE(tasks_completed == 1);
140+
}
141+
142+
THEN("Should not mark task completed when it is not first task") {
143+
// First run
144+
host->GetCPU().RunCPUStep(0, 100);
145+
int tasks_completed_first = 0;
146+
for (int i = 0; i < CPU_BITSET_LENGTH; i++) {
147+
tasks_completed_first += host->GetCPU().state.tasks_performed->Get(i);
148+
}
149+
150+
// Second run (should not mark any tasks)
151+
host->GetCPU().RunCPUStep(0, 100);
152+
int tasks_completed_second = 0;
153+
for (int i = 0; i < CPU_BITSET_LENGTH; i++) {
154+
tasks_completed_second += host->GetCPU().state.tasks_performed->Get(i);
155+
}
156+
157+
REQUIRE(tasks_completed_second == tasks_completed_first);
158+
}
159+
}
160+
}
161+
162+
TEST_CASE("IsOnlyTask functionality", "[tasks]") {
163+
emp::Random random(1);
164+
SymConfigSGP config;
165+
config.SEED(1);
166+
config.MUTATION_RATE(0.0);
167+
config.MUTATION_SIZE(0.002);
168+
config.TRACK_PARENT_TASKS(1);
169+
config.VT_TASK_MATCH(1);
170+
config.ONLY_FIRST_TASK_CREDIT(1);
171+
172+
SGPWorld world(random, &config, LogicTasks);
173+
174+
WHEN("No tasks have been completed yet") {
175+
ProgramBuilder multi_task_program;
176+
multi_task_program.AddNot();
177+
multi_task_program.AddNand();
178+
179+
emp::Ptr<SGPHost> host = emp::NewPtr<SGPHost>(&random, &world, &config, multi_task_program.Build(100));
180+
world.AddOrgAt(host, 0);
181+
182+
THEN("IsOnlyTask should return true for first task") {
183+
// Simulate completing the first task (NOT)
184+
host->GetCPU().state.tasks_performed->Set(0); // Mark NOT as completed
185+
186+
// Create a non const copy of LogicTasks for testing
187+
TaskSet test_tasks = LogicTasks;
188+
bool is_only = test_tasks.IsOnlyTask(host->GetCPU().state, 0);
189+
REQUIRE(is_only == true);
190+
}
191+
}
192+
193+
WHEN("One task has already been completed") {
194+
ProgramBuilder multi_task_program;
195+
multi_task_program.AddNot();
196+
multi_task_program.AddNand();
197+
198+
emp::Ptr<SGPHost> host = emp::NewPtr<SGPHost>(&random, &world, &config, multi_task_program.Build(100));
199+
world.AddOrgAt(host, 0);
200+
201+
THEN("IsOnlyTask should return false for second task") {
202+
// Mark first task as completed
203+
host->GetCPU().state.tasks_performed->Set(0); // NOT completed
204+
205+
// Create a non const copy of LogicTasks for testing
206+
TaskSet test_tasks = LogicTasks;
207+
// Check if second task NAND is the only task
208+
bool is_only = test_tasks.IsOnlyTask(host->GetCPU().state, 1);
209+
REQUIRE(is_only == false);
210+
}
211+
212+
THEN("IsOnlyTask should return true for the first completed task") {
213+
// Mark first task as completed
214+
host->GetCPU().state.tasks_performed->Set(0); // NOT completed
215+
216+
// Create a non const copy of LogicTasks for testing
217+
TaskSet test_tasks = LogicTasks;
218+
// Check if first task is the only task
219+
bool is_only = test_tasks.IsOnlyTask(host->GetCPU().state, 0);
220+
REQUIRE(is_only == true);
221+
}
222+
}
223+
224+
WHEN("Multiple tasks have been completed") {
225+
ProgramBuilder multi_task_program;
226+
multi_task_program.AddNot();
227+
multi_task_program.AddNand();
228+
multi_task_program.AddAnd();
229+
230+
emp::Ptr<SGPHost> host = emp::NewPtr<SGPHost>(&random, &world, &config, multi_task_program.Build(100));
231+
world.AddOrgAt(host, 0);
232+
233+
THEN("IsOnlyTask should return false for any task") {
234+
// Mark multiple tasks
235+
host->GetCPU().state.tasks_performed->Set(0);
236+
host->GetCPU().state.tasks_performed->Set(1);
237+
238+
// Create a non const copy of LogicTasks for testing
239+
TaskSet test_tasks = LogicTasks;
240+
// Check if any task is the only task
241+
bool is_only_not = test_tasks.IsOnlyTask(host->GetCPU().state, 0);
242+
bool is_only_nand = test_tasks.IsOnlyTask(host->GetCPU().state, 1);
243+
bool is_only_and = test_tasks.IsOnlyTask(host->GetCPU().state, 2);
244+
245+
REQUIRE(is_only_not == false);
246+
REQUIRE(is_only_nand == false);
247+
REQUIRE(is_only_and == false);
248+
}
249+
}
250+
}
251+
252+
TEST_CASE("Task completion edge cases", "[tasks]") { // IsSolved Edge casses documentation
253+
emp::Random random(1);
254+
SymConfigSGP config;
255+
config.SEED(1);
256+
config.MUTATION_RATE(0.0);
257+
config.MUTATION_SIZE(0.002);
258+
config.TRACK_PARENT_TASKS(1);
259+
config.VT_TASK_MATCH(1);
260+
config.ONLY_FIRST_TASK_CREDIT(0);
261+
262+
SGPWorld world(random, &config, LogicTasks);
263+
264+
WHEN("Testing output values of 0 and 1") {
265+
ProgramBuilder not_program;
266+
not_program.AddNot();
267+
268+
emp::Ptr<SGPHost> host = emp::NewPtr<SGPHost>(&random, &world, &config, not_program.Build(100));
269+
world.AddOrgAt(host, 0);
270+
271+
THEN("Outputs of 0 and 1 should not be considered valid task completions") {
272+
// Create a NOT task to test with
273+
Task not_task("NOT", 1, 5.0, [](auto &x) { return ~x[0]; });
274+
275+
// Test with output 0
276+
bool is_solved_0 = not_task.IsSolved(host->GetCPU().state, 0);
277+
REQUIRE(is_solved_0 == false);
278+
279+
// Test with output 1
280+
bool is_solved_1 = not_task.IsSolved(host->GetCPU().state, 1);
281+
REQUIRE(is_solved_1 == false);
282+
}
283+
}
54284
}

0 commit comments

Comments
 (0)