diff --git a/source/sgp_mode/SGPHost.h b/source/sgp_mode/SGPHost.h index 1ab70c0c..902b54a0 100644 --- a/source/sgp_mode/SGPHost.h +++ b/source/sgp_mode/SGPHost.h @@ -178,9 +178,20 @@ class SGPHost : public Host { void DecPoints(double amt) { points -= amt; + + if (points < 0){ + points = 0; + } } + void AddPoints(double amt) { points += amt; + + if (points < 0){ + points = 0; + } + + } size_t GetCountofMatchingSymsToInteractWith(){ diff --git a/source/sgp_mode/SGPSymbiont.h b/source/sgp_mode/SGPSymbiont.h index 42bd6145..18668c34 100644 --- a/source/sgp_mode/SGPSymbiont.h +++ b/source/sgp_mode/SGPSymbiont.h @@ -190,12 +190,20 @@ class SGPSymbiont : public Symbiont { } - void AddPoints(double _in) { - points += _in; - } - void DecPoints(double amt) { points -= amt; + + if (points < 0){ + points = 0; + } + } + + void AddPoints(double amt) { + points += amt; + + if (points < 0){ + points = 0; + } } /** diff --git a/source/sgp_mode/SGPWorldSetup.cc b/source/sgp_mode/SGPWorldSetup.cc index f070cf8d..3fd95371 100644 --- a/source/sgp_mode/SGPWorldSetup.cc +++ b/source/sgp_mode/SGPWorldSetup.cc @@ -120,8 +120,7 @@ void SGPWorld::SetupChangingEnvironment() { else if (task_env.GetTaskSet().HasTask("and_not")) { andn_task_id = task_env.GetTaskSet().GetID("and_not"); } - - + size_t orn_task_id = task_env.GetTaskSet().GetSize(); if (task_env.GetTaskSet().HasTask("OR_NOT")) { orn_task_id = task_env.GetTaskSet().GetID("OR_NOT"); @@ -129,8 +128,7 @@ void SGPWorld::SetupChangingEnvironment() { else if (task_env.GetTaskSet().HasTask("or_not")) { orn_task_id = task_env.GetTaskSet().GetID("or_not"); } - - + // grab task ids for NOT, AND, OR size_t not_task_id = task_env.GetTaskSet().GetSize(); if (task_env.GetTaskSet().HasTask("NOT")) { @@ -155,20 +153,21 @@ void SGPWorld::SetupChangingEnvironment() { else if (task_env.GetTaskSet().HasTask("or")) { or_task_id = task_env.GetTaskSet().GetID("or"); } - - // update 0 will flip not-and-or to rewarded and nand-andn-orn to punished - GetTaskEnv().GetHostTaskReq(not_task_id).task_value = -1 * GetTaskEnv().GetHostTaskReq(not_task_id).task_value; - GetTaskEnv().GetSymTaskReq(not_task_id).task_value = -1 * GetTaskEnv().GetSymTaskReq(not_task_id).task_value; - - GetTaskEnv().GetHostTaskReq(and_task_id).task_value = -1 * GetTaskEnv().GetHostTaskReq(and_task_id).task_value; - GetTaskEnv().GetSymTaskReq(and_task_id).task_value = -1 * GetTaskEnv().GetSymTaskReq(and_task_id).task_value; - - GetTaskEnv().GetHostTaskReq(or_task_id).task_value = -1 * GetTaskEnv().GetHostTaskReq(or_task_id).task_value; - GetTaskEnv().GetSymTaskReq(or_task_id).task_value = -1 * GetTaskEnv().GetSymTaskReq(or_task_id).task_value; + + // update 0 will flip nand-andn-orn to rewarded and not-and-or to punished + GetTaskEnv().GetHostTaskReq(nand_task_id).task_value = -1 * GetTaskEnv().GetHostTaskReq(nand_task_id).task_value; + GetTaskEnv().GetSymTaskReq(nand_task_id).task_value = -1 * GetTaskEnv().GetSymTaskReq(nand_task_id).task_value; + + GetTaskEnv().GetHostTaskReq(andn_task_id).task_value = -1 * GetTaskEnv().GetHostTaskReq(andn_task_id).task_value; + GetTaskEnv().GetSymTaskReq(andn_task_id).task_value = -1 * GetTaskEnv().GetSymTaskReq(andn_task_id).task_value; + + GetTaskEnv().GetHostTaskReq(orn_task_id).task_value = -1 * GetTaskEnv().GetHostTaskReq(orn_task_id).task_value; + GetTaskEnv().GetSymTaskReq(orn_task_id).task_value = -1 * GetTaskEnv().GetSymTaskReq(orn_task_id).task_value; begin_update_sig.AddAction( [this, nand_task_id, andn_task_id, orn_task_id, not_task_id, and_task_id, or_task_id]() { if (GetUpdate() % sgp_config.TEMP_CHANGING_ENVIRONMENT_INTERVAL() == 0) { + GetTaskEnv().GetHostTaskReq(nand_task_id).task_value = -1 * GetTaskEnv().GetHostTaskReq(nand_task_id).task_value; GetTaskEnv().GetHostTaskReq(andn_task_id).task_value = -1 * GetTaskEnv().GetHostTaskReq(andn_task_id).task_value; GetTaskEnv().GetHostTaskReq(orn_task_id).task_value = -1 * GetTaskEnv().GetHostTaskReq(orn_task_id).task_value; @@ -177,7 +176,6 @@ void SGPWorld::SetupChangingEnvironment() { GetTaskEnv().GetHostTaskReq(and_task_id).task_value = -1 * GetTaskEnv().GetHostTaskReq(and_task_id).task_value; GetTaskEnv().GetHostTaskReq(or_task_id).task_value = -1 * GetTaskEnv().GetHostTaskReq(or_task_id).task_value; - GetTaskEnv().GetSymTaskReq(nand_task_id).task_value = -1 * GetTaskEnv().GetSymTaskReq(nand_task_id).task_value; GetTaskEnv().GetSymTaskReq(andn_task_id).task_value = -1 * GetTaskEnv().GetSymTaskReq(andn_task_id).task_value; GetTaskEnv().GetSymTaskReq(orn_task_id).task_value = -1 * GetTaskEnv().GetSymTaskReq(orn_task_id).task_value; @@ -185,6 +183,8 @@ void SGPWorld::SetupChangingEnvironment() { GetTaskEnv().GetSymTaskReq(not_task_id).task_value = -1 * GetTaskEnv().GetSymTaskReq(not_task_id).task_value; GetTaskEnv().GetSymTaskReq(and_task_id).task_value = -1 * GetTaskEnv().GetSymTaskReq(and_task_id).task_value; GetTaskEnv().GetSymTaskReq(or_task_id).task_value = -1 * GetTaskEnv().GetSymTaskReq(or_task_id).task_value; + + } } ); diff --git a/source/test/sgp_mode_test/functional_tests/SenseTask_Tasks.test.cc b/source/test/sgp_mode_test/functional_tests/SenseTask_Tasks.test.cc index 326a1ca6..c536fd6a 100644 --- a/source/test/sgp_mode_test/functional_tests/SenseTask_Tasks.test.cc +++ b/source/test/sgp_mode_test/functional_tests/SenseTask_Tasks.test.cc @@ -57,18 +57,18 @@ TEST_CASE("Test host SenseTask instruction after a rewarded task", "[sgp]"){ host_hw.Reset(); host_hw.SetProgram(host_program); world.AssignNewEnvIO(host_hw.GetCPUState()); - - // NOT is currently rewarded. - REQUIRE(world.GetTaskEnv().GetHostTaskReq(not_task_id).task_value > 0); - + + // NOT is currently not rewarded. + REQUIRE(world.GetTaskEnv().GetHostTaskReq(not_task_id).task_value < 0); + // Initial register values host_hw.SetRegisters({3, 2, 5}); // Run host program host_hw.RunCPUStep(4); - THEN("SenseTask puts a 1 into register 1"){ - REQUIRE(host_hw.GetRegister(1) == 1); + THEN("SenseTask puts a 0 into register 1"){ + REQUIRE(host_hw.GetRegister(1) == 0); } } } @@ -110,22 +110,24 @@ TEST_CASE("Test host SenseTask instruction after a punished task", "[sgp]"){ host_hw.SetProgram(host_program); world.AssignNewEnvIO(host_hw.GetCPUState()); - // NAND is currently punished. - REQUIRE(world.GetTaskEnv().GetHostTaskReq(nand_task_id).task_value < 0); + // NAND is not currently punished. + REQUIRE(world.GetTaskEnv().GetHostTaskReq(nand_task_id).task_value > 0); + + // Initial register values host_hw.SetRegisters({7, 12, 9}); // Run host program host_hw.RunCPUStep(5); - - THEN("SenseTask puts a 0 into register 1"){ - REQUIRE(host_hw.GetRegister(1) == 0); + + THEN("SenseTask puts a 1 into register 1"){ + REQUIRE(host_hw.GetRegister(1) == 1); } } } -TEST_CASE("Test symbiont SenseTask instruction after a rewarded task", "[sgp]"){ +TEST_CASE("Test symbiont SenseTask instruction after a punished task", "[sgp]"){ sgpmode::SymConfigSGP config; config.CYCLES_PER_UPDATE(0); config.SEED(61); @@ -149,7 +151,7 @@ TEST_CASE("Test symbiont SenseTask instruction after a rewarded task", "[sgp]"){ // setup correct reward/punishment values for update 0 world.Update(); - WHEN("A symbiont runs a task which is rewarded and then the SenseTask instruction"){ + WHEN("A symbiont runs a task which is punished and then the SenseTask instruction"){ program_t sym_program; prog_builder.AddStartAnchor(sym_program); prog_builder.AddInst(sym_program, "IO", 0); @@ -159,22 +161,22 @@ TEST_CASE("Test symbiont SenseTask instruction after a rewarded task", "[sgp]"){ sym_hw.SetProgram(sym_program); world.AssignNewEnvIO(sym_hw.GetCPUState()); - // NOT is currently rewarded. - REQUIRE(world.GetTaskEnv().GetHostTaskReq(not_task_id).task_value > 0); - + // NOT is currently punished. + REQUIRE(world.GetTaskEnv().GetHostTaskReq(not_task_id).task_value < 0); + // Initial register values sym_hw.SetRegisters({3, 2, 5}); // Run symbiont program - sym_hw.RunCPUStep(4); - - THEN("SenseTask puts a 1 into register 1"){ - REQUIRE(sym_hw.GetRegister(1) == 1); + sym_hw.RunCPUStep(4); + + THEN("SenseTask puts a 0 into register 1"){ + REQUIRE(sym_hw.GetRegister(1) == 0); } } } -TEST_CASE("Test symbiont SenseTask instruction after a punished task", "[sgp]"){ +TEST_CASE("Test symbiont SenseTask instruction after a rewarded task", "[sgp]"){ sgpmode::SymConfigSGP config; config.CYCLES_PER_UPDATE(0); config.SEED(61); @@ -198,7 +200,7 @@ TEST_CASE("Test symbiont SenseTask instruction after a punished task", "[sgp]"){ // setup correct reward/punishment values for update 0 world.Update(); - WHEN("A symbiont runs a task which is punished and then the SenseTask instruction") { + WHEN("A symbiont runs a task which is rewarded and then the SenseTask instruction") { program_t sym_program; prog_builder.AddStartAnchor(sym_program); prog_builder.AddInst(sym_program, "IO", 0); @@ -209,17 +211,17 @@ TEST_CASE("Test symbiont SenseTask instruction after a punished task", "[sgp]"){ sym_hw.SetProgram(sym_program); world.AssignNewEnvIO(sym_hw.GetCPUState()); - // NAND is currently punished. - REQUIRE(world.GetTaskEnv().GetHostTaskReq(nand_task_id).task_value < 0); - + // NAND is currently rewarded. + REQUIRE(world.GetTaskEnv().GetHostTaskReq(nand_task_id).task_value > 0); + // Initial register values sym_hw.SetRegisters({7, 12, 9}); // run symbiont program sym_hw.RunCPUStep(5); - - THEN("SenseTask puts a 0 into register 1"){ - REQUIRE(sym_hw.GetRegister(1) == 0); + + THEN("SenseTask puts a 1 into register 1"){ + REQUIRE(sym_hw.GetRegister(1) == 1); } } } diff --git a/source/test/sgp_mode_test/functional_tests/TempChangingEnvironments.test.cc b/source/test/sgp_mode_test/functional_tests/TempChangingEnvironments.test.cc index 64dbbfd3..61f15bb7 100644 --- a/source/test/sgp_mode_test/functional_tests/TempChangingEnvironments.test.cc +++ b/source/test/sgp_mode_test/functional_tests/TempChangingEnvironments.test.cc @@ -26,7 +26,7 @@ using sgp_host_t = sgpmode::SGPHost; using sgp_sym_t = sgpmode::SGPSymbiont; using program_t = typename world_t::sgp_prog_t; -TEST_CASE("Hosts start with a rewarded task in a temporally changing environment"){ +TEST_CASE("Hosts start with a poisoned task in a temporally changing environment","[sgp]"){ // set up configs sgpmode::SymConfigSGP config; config.TASK_ENV_CFG_PATH("source/test/sgp_mode_test/hardware-test-env.json"); @@ -64,23 +64,23 @@ TEST_CASE("Hosts start with a rewarded task in a temporally changing environment world.Update(); size_t host_not_count = world.GetHostTaskSuccesses().at(not_task_id); - THEN("The host initially gains points for completing its task") { + THEN("The host initially gains loses for completing its task") { REQUIRE(host_not_count == 1); - REQUIRE(host_not_only->GetPoints() == 5); + REQUIRE(host_not_only->GetPoints() == 0); } // event update world.Update(); host_not_count += world.GetHostTaskSuccesses().at(not_task_id); - THEN("After the environment changes, the host loses points for completing its task") { + THEN("After the environment changes, the host gains points for completing its task") { REQUIRE(host_not_count == 2); - REQUIRE(host_not_only->GetPoints() == 0); + REQUIRE(host_not_only->GetPoints() == 5); } } } -TEST_CASE("Symbionts start with a rewarded task in a temporally changing environment"){ +TEST_CASE("Symbionts start with a poisoned task in a temporally changing environment", "[sgp]"){ // set up configs sgpmode::SymConfigSGP config; config.TASK_ENV_CFG_PATH("source/test/sgp_mode_test/hardware-test-env.json"); @@ -120,23 +120,23 @@ TEST_CASE("Symbionts start with a rewarded task in a temporally changing environ world.Update(); size_t sym_not_count = world.GetSymTaskSuccesses().at(not_task_id); - THEN("The symbiont initially gains points for completing its task") { + THEN("The symbiont initially loses points for completing its task") { REQUIRE(sym_not_count == 1); - REQUIRE(symbiont_not_only->GetPoints() == 5); + REQUIRE(symbiont_not_only->GetPoints() == 0); } // event update world.Update(); sym_not_count += world.GetSymTaskSuccesses().at(not_task_id); - THEN("After the environment changes, the symbiont loses points for completing its task") { + THEN("After the environment changes, the symbiont gains points for completing its task") { REQUIRE(sym_not_count == 2); - REQUIRE(symbiont_not_only->GetPoints() == 0); + REQUIRE(symbiont_not_only->GetPoints() == 5); } } } -TEST_CASE("Hosts start with a punished task in a temporally changing environment", "[sgp]") { +TEST_CASE("Hosts start with a rewarded task in a temporally changing environment", "[sgp]") { // set up configs sgpmode::SymConfigSGP config; config.TASK_ENV_CFG_PATH("source/test/sgp_mode_test/hardware-test-env.json"); @@ -174,24 +174,24 @@ TEST_CASE("Hosts start with a punished task in a temporally changing environment world.Update(); size_t host_orn_count = world.GetHostTaskSuccesses().at(or_not_task_id); - THEN("The host initially loses points for completing its task") { + THEN("The host initially gains points for completing its task") { REQUIRE(host_orn_count == 1); - REQUIRE(host_orn_only->GetPoints() == -5); + REQUIRE(host_orn_only->GetPoints() == 5); } // event update world.Update(); host_orn_count += world.GetHostTaskSuccesses().at(or_not_task_id); - THEN("After the environment changes, the host gains points for completing its task") { + THEN("After the environment changes, the host loses points for completing its task") { REQUIRE(host_orn_count == 3); - REQUIRE(host_orn_only->GetPoints() == 5); + REQUIRE(host_orn_only->GetPoints() == 0); } } } -TEST_CASE("Symbionts start with a punished task in a temporally changing environment", "[sgp]") { +TEST_CASE("Symbionts start with a rewarded task in a temporally changing environment", "[sgp]") { // set up configs sgpmode::SymConfigSGP config; config.TASK_ENV_CFG_PATH("source/test/sgp_mode_test/hardware-test-env.json"); @@ -231,18 +231,18 @@ TEST_CASE("Symbionts start with a punished task in a temporally changing environ world.Update(); size_t sym_nand_count = world.GetSymTaskSuccesses().at(nand_task_id); - THEN("The symbiont initially loses points for completing its task") { + THEN("The symbiont initially gains points for completing its task") { REQUIRE(sym_nand_count == 1); - REQUIRE(symbiont_nand_only->GetPoints() == -5); + REQUIRE(symbiont_nand_only->GetPoints() == 5); } // event update world.Update(); sym_nand_count += world.GetSymTaskSuccesses().at(nand_task_id); - THEN("After the environment changes, the symbiont gains points for completing its tasks") { + THEN("After the environment changes, the symbiont loses points for completing its tasks") { REQUIRE(sym_nand_count == 3); - REQUIRE(symbiont_nand_only->GetPoints() == 5); + REQUIRE(symbiont_nand_only->GetPoints() == 0); } } } diff --git a/source/test/sgp_mode_test/unit_tests/SGPHost.test.cc b/source/test/sgp_mode_test/unit_tests/SGPHost.test.cc index dd954812..79401dca 100644 --- a/source/test/sgp_mode_test/unit_tests/SGPHost.test.cc +++ b/source/test/sgp_mode_test/unit_tests/SGPHost.test.cc @@ -282,4 +282,31 @@ TEST_CASE("ProcessOutputBuffer", "[sgp][sgp-unit]") { } } } +} + + +TEST_CASE("Check that hosts and syms can't have negative points", "[sgp][sgp-unit]"){ + using world_t = sgpmode::SGPWorld; + using cpu_state_t = sgpmode::CPUState; + using hw_spec_t = sgpmode::SGPHardwareSpec; + using sgp_host_t = sgpmode::SGPHost; + using sgp_sym_t = sgpmode::SGPSymbiont; + GIVEN("A host and sym starting with zero points"){ + emp::Random random(31); + sgpmode::SymConfigSGP config; + config.TASK_ENV_CFG_PATH("source/test/sgp_mode_test/hardware-test-env.json"); + world_t world(random, &config); + auto& prog_builder = world.GetProgramBuilder(); + emp::Ptr host = emp::NewPtr(&random, &world, &config, prog_builder.CreateReproProgram(100)); + emp::Ptr sym = emp::NewPtr(&random, &world, &config, prog_builder.CreateNotProgram(100)); + + WHEN("points are added to make total points negative"){ + sym->AddPoints(-100); + host->AddPoints(-100); + THEN("point value should be set to zero"){ + REQUIRE(host->GetPoints() == 0); + REQUIRE(sym->GetPoints() == 0); + } + } + } } \ No newline at end of file