-
Notifications
You must be signed in to change notification settings - Fork 20
ClassDefinition_step5
Objects can be stored in any GAML variable — global, species, local, etc.
species node_agent skills: [moving] {
/** Incoming messages queued for this agent. */
list<message_object> inbox <- [];
/** Current velocity vector. */
vec2 velocity <- vec2(dx: rnd(2.0) - 1.0, dy: rnd(2.0) - 1.0);
}
global {
geometry shape <- square(100);
init {
create node_agent number: 10;
}
}
Objects follow GAML value semantics — assigning to a variable copies the reference, not the object. Both agents hold a reference to the same object in memory:
species node_agent skills: [moving] {
list<message_object> inbox <- [];
/** Receives a message object. */
action receive_message(message_object msg) {
inbox <+ msg;
}
/**
* Creates and returns a new message object.
* Returning an object from an agent action is identical to returning any other value.
*/
message_object compose(string msg_content, int msg_priority) {
return message_object(sender_name: name,
content: msg_content,
priority: msg_priority);
}
}
global {
init {
create node_agent number: 5;
}
}
global {
init {
node_agent sender <- first(node_agent);
message_object m1 <- sender.compose("Hello world", 2);
node_agent recipient <- last(node_agent);
ask recipient { do receive_message(m1); }
write recipient.name + " inbox size: " + length(recipient.inbox);
// Both sender and recipient hold a reference to THE SAME object
write "Same object? " + (m1 = recipient.inbox[0]); // true: reference equality
}
}
Actions in any class can return objects — including actions in agents:
vec2 add(vec2 other) {
return vec2(dx: dx + other.dx, dy: dy + other.dy);
}
This enables chaining:
vec2 combined <- v1.add(v2).scale(0.5);
// Creates a sum, then scales it — zero intermediate variables
experiment Advanced_Features title: "Advanced Features" type: gui {
/** Number of nodes — also used as a parameter in the GUI. */
parameter "Number of nodes" var: nb_nodes min: 2 max: 50 category: "Setup";
output {
display Nodes title: "Nodes" type: 2d {
species node_agent;
}
}
}
The nb_nodes integer parameter can be used in the model to control species population size.
Objects inside agent collections can be any type — including polymorphic lists:
// Send messages between random pairs
loop i from: 1 to: 3 {
node_agent s <- any(node_agent);
node_agent r <- any(node_agent where (each != s));
if r != nil {
message_object msg <- s.compose("ping #" + i, i);
ask r { do receive_message(msg); }
}
}
// Accumulate all messages across all agents
list<message_object> all_msgs <- node_agent accumulate each.inbox;
list<message_object> sorted <- all_msgs sort_by (-each.priority);
The equality operator = on objects tests reference identity by default — two objects are the same iff they are the exact same instance:
vec2 a <- vec2(dx: 3.0, dy: 4.0);
vec2 b <- vec2(dx: 3.0, dy: 4.0); // different object, same values
vec2 c <- a; // same reference as a
write "a = b (same reference)? " + (a = b); // false (different instances)
write "a = c (same reference)? " + (a = c); // true (same instance)
Objects can be used as keys in maps since they support identity-based hashing:
map<vec2, string> labels;
labels[a] <- "origin vector";
labels[b] <- "copy vector";
write "labels[a] = " + labels[a]; // "origin vector"
write "labels[b] = " + labels[b]; // "copy vector"
write "labels[c] = " + labels[c]; // "origin vector" — c shares ref with a
The advanced features model shows how objects and species work together in a complete simulation:
// Supporting classes
class vec2 {
float dx <- 0.0;
float dy <- 0.0;
float norm() { return sqrt(dx ^ 2 + dy ^ 2); }
vec2 add(vec2 other) { return vec2(dx: dx + other.dx, dy: dy + other.dy); }
vec2 scale(float factor) { return vec2(dx: dx * factor, dy: dy * factor); }
string to_string() { return "(" + (dx with_precision 2) + ", " + (dy with_precision 2) + ")"; }
}
class message_object {
string sender_name <- "unknown";
string content <- "";
int priority <- 1;
bool read_flag <- false;
string consume() { read_flag <- true; return content; }
string to_string() { return "[msg p=" + priority + (read_flag ? " ✓" : " ")
+ "] from=" + sender_name + " : " + content; }
}
// Species with objects as attributes
species node_agent skills: [moving] {
list<message_object> inbox <- [];
vec2 velocity <- vec2(dx: rnd(2.0) - 1.0, dy: rnd(2.0) - 1.0);
float energy <- 100.0;
action receive_message(message_object msg) {
inbox <+ msg;
}
int process_inbox() {
int count <- length(inbox);
loop msg over: inbox {
string text <- msg.consume();
energy <- energy - msg.priority * 0.5;
}
inbox <- [];
return count;
}
message_object compose(string msg_content, int msg_priority) {
return message_object(sender_name: name, content: msg_content, priority: msg_priority);
}
reflex drift {
location <- {(location.x + velocity.dx) mod world.shape.width,
(location.y + velocity.dy) mod world.shape.height};
}
reflex check_mail when: !empty(inbox) {
int n <- process_inbox();
}
reflex recharge {
energy <- min(100.0, energy + 0.2);
}
aspect default {
float r <- max(1.0, energy / 20.0);
draw circle(r) color: rgb(int(energy * 2.55), 100, 50) border: #white;
if !empty(inbox) {
draw string(length(inbox)) at: location + {0, -r - 0.5}
color: #yellow size: 2.0;
}
}
}
global {
geometry shape <- square(100);
int nb_nodes <- 10;
init { create node_agent number: nb_nodes; }
message_object create_random_message() {
return message_object(sender_name: "system", content: "test", priority: rnd(5));
}
}
experiment Advanced_Features title: "Advanced Features" type: gui {
parameter "Number of nodes" var: nb_nodes min: 2 max: 50 category: "Setup";
output {
display Nodes title: "Nodes" type: 2d {
species node_agent;
}
}
}
| Feature | Description |
|---|---|
| Objects as agent attributes |
list<message> inbox <- []; inside species |
| Passing objects between agents | Action arguments — reference is shared |
| Returning objects from actions | Same syntax as returning any value |
| Chaining action returns |
v1.add(v2).scale(0.5) — no intermediate vars |
| Object identity |
a = b returns true only if same instance |
| Objects as map keys | map<ClassName, T> m; m[an_object] <- value; |
| Experiment parameters | parameter "Label" var: class_instance_type; |
| Aggregating objects | Species accumulate each.obj_attr |
- Inheritance — Species
- Defining Actions and Behaviors
- Built-in Species — species that come with GAMA (matrix, field, graph)
- Installation and Launching
- Workspace, Projects and Models
- Editing Models
- Running Experiments
- Running Headless
- Preferences
- Troubleshooting
- Introduction
- Manipulate basic Species
- Global Species
- Defining Advanced Species
- Defining GUI Experiment
- Classes and Objects
- Exploring Models
- Optimizing Models
- Multi-Paradigm Modeling
- Manipulate OSM Data
- Cleaning OSM Data
- Diffusion
- Using Database
- Using Dataframes
- Using FIPA ACL
- Using BDI with BEN
- Using Driving Skill
- Manipulate dates
- Manipulate lights
- Using comodel
- Save and restore Simulations
- Using network
- Writing Unit Tests
- Ensure model's reproducibility
- Going further with extensions
- Built-in Species
- Built-in Skills
- Built-in Architecture
- Statements
- Data Type
- File Type
- Stats Extension
- Sound Extension
- BDI Extension
- FIPA Skill
- Expressions
- Exhaustive list of GAMA Keywords
- Installing the development version
- Developing Extensions
- Introduction to GAMA Java API
- Using GAMA flags
- Creating a release of GAMA
- Documentation generation
- Predator Prey
- Road Traffic
- Incremental Model
- Luneray's flu
- BDI Agents
- Forager RL
- SIR Analysis
- 3D Model