Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
ea9ebcc
adding event handling files
kelleyde May 18, 2026
77083bb
ChangingEventsHandler functions
kelleyde May 25, 2026
804ccd9
stash old files
kelleyde May 31, 2026
2dd517d
stash old files
kelleyde May 31, 2026
cb91625
update old files
kelleyde May 31, 2026
37d651b
new changes up to date
kelleyde May 31, 2026
a11f577
LoadEvents, DeleteEvents
kelleyde Jun 1, 2026
0bf3438
ProcessEvents, DeleteEvents, SortEvents
kelleyde Jun 8, 2026
2f95355
Resolve merge conflicts with main
amlalejini Jun 9, 2026
6aaff06
Remove accidentally duplicated function in Host.h
amlalejini Jun 9, 2026
197faa1
Move event system into its own directory. Separate event type definit…
amlalejini Jun 9, 2026
48da76e
Start separating out different event types
amlalejini Jun 9, 2026
1e6d4e0
Continue updating event parsing from json
amlalejini Jun 10, 2026
26fd923
Fix many compilation errors in current draft of event system
amlalejini Jun 11, 2026
ca6104e
Implement one-time event processing function
amlalejini Jun 11, 2026
596c718
Refactor event processing functions in event manager
amlalejini Jun 11, 2026
7c3f88b
Implement process function for TaskValueEvent, make it easier to add …
amlalejini Jun 11, 2026
62c80b4
Integrate events system into world, remove temporary solution to conf…
amlalejini Jun 11, 2026
64128d7
Remove debugging print statements
amlalejini Jun 12, 2026
13ce5f2
Move temp changing environment and sense instruction tests into need …
amlalejini Jun 12, 2026
11b9d83
Ignore Data/ directory
amlalejini Jun 12, 2026
8ed6304
Clean up event system code, implement manual AddEvent functions in Ev…
amlalejini Jun 12, 2026
6ad9b16
Updates during code review
amlalejini Jun 12, 2026
fee13f7
Merge pull request #1 from amlalejini/event-system-lalejini
kelleyde Jun 12, 2026
91a2276
commiting changes to SGPWorldSetup.cc to pull events files
kelleyde Jun 14, 2026
19c8e46
Merge branch 'sgp-copy' of github.com:kelleyde/SymbulationEmp into sg…
kelleyde Jun 14, 2026
3151e52
add changes to Makefile
kelleyde Jun 19, 2026
1db449a
TaskValue events tests
kelleyde Jun 23, 2026
7864ddc
update task-value events tests, ProgramBuilder.h, add event json files
kelleyde Jul 7, 2026
ff4400a
fix typo in comment ProgramBuilder CreateNANDProgram
kelleyde Jul 8, 2026
d9dc96b
fixing merge conflicts with all the other updates to main
anyaevostinar Jul 13, 2026
b766f82
fixing last merge conflict remnants
anyaevostinar Jul 13, 2026
6ee9e79
Merge pull request #2 from anyaevostinar/kelleyde-sgp-copy
kelleyde Jul 14, 2026
319b50e
Merge main into event system pr branch
amlalejini Jul 30, 2026
f1bafd1
Fix unresolved merge conflict from prev merge
amlalejini Jul 30, 2026
470cea2
Add function docstrings to json utils
amlalejini Jul 30, 2026
136fb65
Add doc strings for Event.h
amlalejini Jul 30, 2026
8280e06
Add doc strings in ExampleEvent.h
amlalejini Jul 30, 2026
2af3c7f
Add docstrings for TaskValueEvent
amlalejini Jul 30, 2026
8bf8757
Add doc strings to EventManager
amlalejini Jul 30, 2026
f1733cc
Add doc strings to EventTiming
amlalejini Jul 30, 2026
a048db0
Add doc strings to EventTypeDefinition
amlalejini Jul 30, 2026
4b93164
Add doc strings for EventTypeLibrary
amlalejini Jul 30, 2026
4a3425a
Update variable names for readability in Event.h as per PR review
amlalejini Jul 30, 2026
5e34461
Update events tests
amlalejini Jul 30, 2026
de892e5
Update spacing for consistency
amlalejini Jul 30, 2026
4cd9759
Merge branch 'main' into sgp-copy
amlalejini Jul 30, 2026
537df74
Add events file cfg to sgpmode tests, fix pointer that wasn't being d…
amlalejini Jul 30, 2026
37ed4ee
Add no-events.json events file
amlalejini Jul 30, 2026
9a8a494
Fix issues with config files not being found, add emp_assert to make …
amlalejini Jul 30, 2026
3b3887f
Merge pull request #3 from amlalejini/sgp-copy
kelleyde Jul 31, 2026
27aa395
Merge branch 'main' into sgp-copy
anyaevostinar Aug 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ log.txt
*.json
*_test_output/
*_output/
Data/*


5 changes: 3 additions & 2 deletions source/catch/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "../test/pgg_mode_test/PGGWorld.test.cc"

//SGP mode Old tests (need to update before moving)
#include "../test/sgp_mode_test/functional_tests/TaskValueEvent.test.cc"
#include "../test/sgp_mode_test/unit_tests/ProgramBuilder.test.cc"
#include "../test/sgp_mode_test/functional_tests/HealthMode.test.cc"
#include "../test/sgp_mode_test/unit_tests/SGPWorldSetup.test.cc"
Expand Down Expand Up @@ -64,11 +65,11 @@
#include "../test/sgp_mode_test/unit_tests/SGPCureHosts.test.cc"
#include "../test/sgp_mode_test/unit_tests/SGPWorldData.test.cc"

#include "../test/sgp_mode_test/functional_tests/SenseTask_Tasks.test.cc"
// #include "../test/sgp_mode_test/functional_tests/SenseTask_Tasks.test.cc"
#include "../test/sgp_mode_test/functional_tests/NutrientMode.test.cc"
#include "../test/sgp_mode_test/functional_tests/SGPHost_SGPSymbiont.test.cc"
#include "../test/sgp_mode_test/functional_tests/SGPSymbiont_Reproduce.test.cc"
#include "../test/sgp_mode_test/functional_tests/TempChangingEnvironments.test.cc"
// #include "../test/sgp_mode_test/functional_tests/TempChangingEnvironments.test.cc"
#include "../test/sgp_mode_test/functional_tests/SGPWorld.test.cc"
#include "../test/sgp_mode_test/functional_tests/PopulationStructure.test.cc"

Expand Down
6 changes: 3 additions & 3 deletions source/default_mode/Host.h
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ class Host: public Organism {
*
* Purpose: To set the organism's world position
*/
virtual void SetLocation(emp::WorldPosition _in) { location = _in; }
virtual void SetLocation(emp::WorldPosition _in) {location = _in;}


/**
Expand Down Expand Up @@ -652,7 +652,7 @@ class Host: public Organism {
*/
emp::Ptr<Organism> RemoveSymbiont(int index) {
int num_syms = syms.size();
if (index < 1 || index > num_syms) {
if(index < 1 || index > num_syms) {
return nullptr;
} else {
emp::Ptr<Organism> to_remove = syms[index-1];
Expand Down Expand Up @@ -802,7 +802,7 @@ class Host: public Organism {
double mutation_rate = my_config->HOST_MUTATION_RATE();
if (mutation_rate == -1) mutation_rate = my_config->MUTATION_RATE();

if (random->GetDouble(0.0, 1.0) <= mutation_rate) {
if(random->GetDouble(0.0, 1.0) <= mutation_rate){
interaction_val += random->GetNormal(0.0, mutation_size);
if (interaction_val < -1) interaction_val = -1;
else if (interaction_val > 1) interaction_val = 1;
Expand Down
2 changes: 1 addition & 1 deletion source/default_mode/Symbiont.h
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ class Symbiont: public Organism {
*
* Purpose: To set the organism's world position
*/
void SetLocation(emp::WorldPosition _in) { location = _in; }
void SetLocation(emp::WorldPosition _in) {location = _in;}

/**
* Input: None
Expand Down
73 changes: 73 additions & 0 deletions source/json/json_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#pragma once

#include "json.hpp"

#include "emp/base/vector.hpp"

#include <string>

namespace sym_json {

/**
* Purpose: Convenience function for more easily getting a value from a json field
* with a default return value if the field doesn't exist.
*
* Input: json object to access, field to access in json object, and a default
* value to return if the field doesn't exist in the json object.
*
* Output: Either the accessed field value or the provided default value.
*
*/
template<typename RET_TYPE>
RET_TYPE GetVal(
nlohmann::json& json,
const std::string& field,
RET_TYPE default_val
) {
return (json.contains(field)) ?
static_cast<RET_TYPE>(json[field]) :
default_val;
}

/**
* Purpose: Convenience function for more easily getting a value from a json field.
* This version of the GetVal function assumes that the field exists.
*
* Input: json object to access, field to access in json object
*
* Output: The accessed field value
*
*/
template<typename RET_TYPE>
RET_TYPE GetVal(
nlohmann::json& json,
const std::string& field
) {
emp_assert(json.contains(field));
return static_cast<RET_TYPE>(json[field]);
}

/**
* Purpose: Validate that specified strings exist as fields inside of a json object.
* This function is useful for asserting that required/expected fields
* exist.
*
* Input: json object to check, fields to check in json object
*
* Output: Boolean indicating whether all given fields are contained in the json
* object.
*
*/
bool ValidateFieldsJSON(
const nlohmann::json& json_line,
const emp::vector<std::string>& fields
) {
for (const std::string& name : fields) {
if (!json_line.contains(name)) {
return false;
}
}
return true;
}

}
4 changes: 2 additions & 2 deletions source/sgp_mode/ProgramBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -573,9 +573,9 @@ class ProgramBuilder {
start_tag
);
// Add not instruction
AddInst(program, io_op);
AddInst(program, io_op);
AddTask_Not(program); // Add not task
AddInst(program, io_op);
AddInst(program, io_op);
AddInst(program, io_op, 1);
AddTask_Nand(program); // Add nand task, IO will happen at start of next time through genome
// Nop filler is length minus current size + repro instructions
Expand Down
9 changes: 5 additions & 4 deletions source/sgp_mode/SGPConfigSetup.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,11 @@ EMP_EXTEND_CONFIG(SymConfigSGP, SymConfigBase,
VALUE(HOST_ONLY_FIRST_TASK_CREDIT, bool, false, "Only give host credit for one task (whatever they do first)?"),
VALUE(SYM_ONLY_FIRST_TASK_CREDIT, bool, false, "Only give sym credit for one task (whatever they do first)?"),

GROUP(TEMP_CHANGING_ENVIRONMENT, "Temporally changing environment settings (task rewards change over time)"),
VALUE(ENABLE_TEMP_CHANGING_ENVIRONMENT, bool, false, "Do task reward values change over time?"),
VALUE(TEMP_CHANGING_ENVIRONMENT_INTERVAL, size_t, 100, "How many updates elapse between task reward value shuffling?"),
VALUE(TEMP_CHANGING_ENVIRONMENT_ORG_TYPE, std::string, "static", "Can organisms sense task reward values? (plastic-both: both symbionts and hosts can sense whether tasks are rewarded; static: neither hosts nor symbiont can sense whether tasks are rewarded)"),
GROUP(EVENTS, "Events settings"),
VALUE(EVENTS_CFG_PATH, std::string, "events.json", "JSON file that provides event configuration"),

GROUP(INSTRUCTIONS, "Instruction settings"),
VALUE(SENSE_TASK_INSTRUCTION, bool, false, "Should sense task instruction be included in the instruction set?"),

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably clearly call it 'SenseTask' so that it's obvious what the name of the instruction is

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, totally agree. Just in case there are future enable/disable config options, what about INCLUDE_INSTRUCTION_SenseTask? to make it super clear what we're toggling


GROUP(DATA, "Data settings"),
VALUE(PRINT_INTERVAL, size_t, 1, "How often to print run status")
Expand Down
25 changes: 21 additions & 4 deletions source/sgp_mode/SGPWorld.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "hardware/SGPHardwareSpec.h"
#include "hardware/GenomeLibrary.h"
#include "hardware/SGPHardware.h"
#include "events/EventManager.h"

#include "emp/Evolve/World_structure.hpp"
#include "emp/data/DataNode.hpp"
Expand Down Expand Up @@ -49,6 +50,7 @@ class SGPWorld : public SymWorld {
using task_io_t = typename task_io_bank_t::TaskIO;
using mutator_t = SGPMutator<sgp_prog_t, Library>;
using sgp_prog_rectifier_t = sgpl::OpCodeRectifier<Library>;
using event_manager_t = EventManager<SGPWorld>;

using fun_sym_do_birth_t = std::function<emp::WorldPosition(
emp::Ptr<sgp_sym_t>, /* symbiont baby ptr */
Expand Down Expand Up @@ -381,6 +383,7 @@ class SGPWorld : public SymWorld {
size_t max_world_size; // Maximum number of locations in the world
ReproductionQueue repro_queue; // Stores which organisms are queued for reproduction
tasks::LogicTaskEnvironment task_env; // Manages task set, task requirements, and task rewards
event_manager_t event_manager;
// TODO - Consider having symbiont rectifier and host rectifier
// -> Symbiont-specific instructions wouldn't be in host's instruction set
sgp_prog_rectifier_t opcode_rectifier; // Used to "disable" instructions at runtime based on run configuration
Expand Down Expand Up @@ -549,6 +552,7 @@ class SGPWorld : public SymWorld {
void SetupFindHostForHorizontalTransmission();
void SetupHostSymInteractions();
void SetupTaskEnvironment();
void SetupEvents();
void SetupMutator();
void SetupStressInteractions();
void SetupHealthInteractions();
Expand Down Expand Up @@ -576,7 +580,6 @@ class SGPWorld : public SymWorld {
}



// Utility function to get cpu state from an org pointer
sgp_cpu_peripheral_t& GetCPUState(emp::Ptr<Organism> org_ptr) {
return (org_ptr->IsHost()) ?
Expand Down Expand Up @@ -660,12 +663,22 @@ class SGPWorld : public SymWorld {
size_t GetTaskCount() const { return task_env.GetTaskCount(); }

/* Accessor for host task profiles */
const emp::BitVector& GetHostTaskProfile(const sgp_host_t& host){return fun_get_host_task_profile(host);}
const emp::BitVector& GetHostTaskProfile(const sgp_host_t& host) { return fun_get_host_task_profile(host); }

/* Accessor for symbiont task profiles */
const emp::BitVector& GetSymbiontTaskProfile(const sgp_sym_t& symbiont){return fun_get_sym_task_profile(symbiont);}
const emp::BitVector& GetSymbiontTaskProfile(const sgp_sym_t& symbiont) { return fun_get_sym_task_profile(symbiont); }

/**
* Purpose: Accessor for event manager (const)
*/
const event_manager_t& GetEventManager() const { return event_manager; }

/**
/**
* Purpose: Accessor for event manager
*/
event_manager_t& GetEventManager() { return event_manager; }

/**
* Input: A host, a symbiont, the value of a task before applying nutrient interaction, and the task id.
* Output: The change in the points the host will gain from the task after the nutrient interaction.
* Purpose: To calculate the configured nutrient interaction for the given symbiont and task
Expand Down Expand Up @@ -824,6 +837,10 @@ class SGPWorld : public SymWorld {
*/
void Update() override {
emp_assert(setup);
// NOTE - When do we want events to occur? Typically, I think we want them

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, I think they have to just be the first thing that happens in an update. So let's remove the comment

// as the *very* first thing that happens on an update. E.g., changing
// a task value, etc.
event_manager.ProcessEvents(*this);
begin_update_sig.Trigger();
// Handle resource inflow
// TODO - implement inflow configuration
Expand Down
104 changes: 8 additions & 96 deletions source/sgp_mode/SGPWorldSetup.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@
#include "../utils.h"

#include "sgpl/utility/ThreadLocalRandom.hpp"

#include "emp/datastructs/map_utils.hpp"
#include "emp/tools/string_utils.hpp"
#include "emp/math/math.hpp"



// TODO - assert that sym / host has program
namespace sgpmode {

Expand Down Expand Up @@ -75,6 +73,9 @@ void SGPWorld::Setup() {
// Setup any host-symbiont interactions
SetupHostSymInteractions();

// Load events
SetupEvents();

// CureHost signal
// TODO: move to default? Figure out how to remove duplication
if (sgp_config.CURE()) {
Expand All @@ -87,10 +88,6 @@ void SGPWorld::Setup() {
);
}

if (sgp_config.ENABLE_TEMP_CHANGING_ENVIRONMENT()) {
SetupChangingEnvironment();
}

SetupHosts(&POP_SIZE);
// NOTE - any way to clean this up a little? Or, add some explanatory comments.
long unsigned int total_syms = POP_SIZE * start_moi;
Expand All @@ -101,95 +98,6 @@ void SGPWorld::Setup() {
setup = true;
}

void SGPWorld::SetupChangingEnvironment() {
// on setup, set NAND, AND-NOT, OR-NOT to be negative (at update zero)
// then during each interval apply *-1 to the changing tasks

size_t nand_task_id = task_env.GetTaskSet().GetSize();
if (task_env.GetTaskSet().HasTask("NAND")) {
nand_task_id = task_env.GetTaskSet().GetID("NAND");
}
else if (task_env.GetTaskSet().HasTask("nand")) {
nand_task_id = task_env.GetTaskSet().GetID("nand");
}

size_t andn_task_id = task_env.GetTaskSet().GetSize();
if (task_env.GetTaskSet().HasTask("AND_NOT")) {
andn_task_id = task_env.GetTaskSet().GetID("AND_NOT");
}
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");
}
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")) {
not_task_id = task_env.GetTaskSet().GetID("NOT");
}
else if (task_env.GetTaskSet().HasTask("not")) {
not_task_id = task_env.GetTaskSet().GetID("not");
}

size_t and_task_id = task_env.GetTaskSet().GetSize();
if (task_env.GetTaskSet().HasTask("AND")) {
and_task_id = task_env.GetTaskSet().GetID("AND");
}
else if (task_env.GetTaskSet().HasTask("and")) {
and_task_id = task_env.GetTaskSet().GetID("and");
}

size_t or_task_id = task_env.GetTaskSet().GetSize();
if (task_env.GetTaskSet().HasTask("OR")) {
or_task_id = task_env.GetTaskSet().GetID("OR");
}
else if (task_env.GetTaskSet().HasTask("or")) {
or_task_id = task_env.GetTaskSet().GetID("or");
}

// 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;

GetTaskEnv().GetHostTaskReq(not_task_id).task_value = -1 * GetTaskEnv().GetHostTaskReq(not_task_id).task_value;
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;

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;


}
}
);
}

void SGPWorld::DisableConfigurableInstructions() {

// Knock out any mode-related instructions that shouldn't be active for this run
Expand Down Expand Up @@ -223,7 +131,7 @@ void SGPWorld::DisableConfigurableInstructions() {

// if temporally changing environment are off, or if organisms aren't allowed to sense their environment,
// disable the SenseTask instruction
if (!sgp_config.ENABLE_TEMP_CHANGING_ENVIRONMENT() || sgp_config.TEMP_CHANGING_ENVIRONMENT_ORG_TYPE() == "static") {
if (!sgp_config.SENSE_TASK_INSTRUCTION()) {
del_inst(
opcode_rectifier.mapper.begin(),
opcode_rectifier.mapper.end(),
Expand Down Expand Up @@ -549,6 +457,10 @@ void SGPWorld::SetupTaskEnvironment() {
);
}

void SGPWorld::SetupEvents() {
event_manager.LoadEventsFromJSON(sgp_config.EVENTS_CFG_PATH(), *this);
}

void SGPWorld::SetupMutator() {
// NOTE - can add more flexibility to mutator
mutator.SetPerBitMutationRate(sgp_config.SGP_MUT_PER_BIT_RATE());
Expand Down
Loading