agentjs-core
Version:
A comprehensive agent-based modeling framework with built-in p5.js visualization
1,880 lines • 648 kB
JavaScript
var Qo = Object.defineProperty;
var Ko = (s, t, e) => t in s ? Qo(s, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : s[t] = e;
var M = (s, t, e) => (Ko(s, typeof t != "symbol" ? t + "" : t, e), e);
import * as j from "@tensorflow/tfjs";
function Zo(s) {
return s && s.__esModule && Object.prototype.hasOwnProperty.call(s, "default") ? s.default : s;
}
var Us = { exports: {} };
(function(s) {
var t = Object.prototype.hasOwnProperty, e = "~";
function i() {
}
Object.create && (i.prototype = /* @__PURE__ */ Object.create(null), new i().__proto__ || (e = !1));
function n(c, l, h) {
this.fn = c, this.context = l, this.once = h || !1;
}
function o(c, l, h, u, d) {
if (typeof h != "function")
throw new TypeError("The listener must be a function");
var f = new n(h, u || c, d), g = e ? e + l : l;
return c._events[g] ? c._events[g].fn ? c._events[g] = [c._events[g], f] : c._events[g].push(f) : (c._events[g] = f, c._eventsCount++), c;
}
function r(c, l) {
--c._eventsCount === 0 ? c._events = new i() : delete c._events[l];
}
function a() {
this._events = new i(), this._eventsCount = 0;
}
a.prototype.eventNames = function() {
var l = [], h, u;
if (this._eventsCount === 0)
return l;
for (u in h = this._events)
t.call(h, u) && l.push(e ? u.slice(1) : u);
return Object.getOwnPropertySymbols ? l.concat(Object.getOwnPropertySymbols(h)) : l;
}, a.prototype.listeners = function(l) {
var h = e ? e + l : l, u = this._events[h];
if (!u)
return [];
if (u.fn)
return [u.fn];
for (var d = 0, f = u.length, g = new Array(f); d < f; d++)
g[d] = u[d].fn;
return g;
}, a.prototype.listenerCount = function(l) {
var h = e ? e + l : l, u = this._events[h];
return u ? u.fn ? 1 : u.length : 0;
}, a.prototype.emit = function(l, h, u, d, f, g) {
var p = e ? e + l : l;
if (!this._events[p])
return !1;
var m = this._events[p], y = arguments.length, b, x;
if (m.fn) {
switch (m.once && this.removeListener(l, m.fn, void 0, !0), y) {
case 1:
return m.fn.call(m.context), !0;
case 2:
return m.fn.call(m.context, h), !0;
case 3:
return m.fn.call(m.context, h, u), !0;
case 4:
return m.fn.call(m.context, h, u, d), !0;
case 5:
return m.fn.call(m.context, h, u, d, f), !0;
case 6:
return m.fn.call(m.context, h, u, d, f, g), !0;
}
for (x = 1, b = new Array(y - 1); x < y; x++)
b[x - 1] = arguments[x];
m.fn.apply(m.context, b);
} else {
var v = m.length, w;
for (x = 0; x < v; x++)
switch (m[x].once && this.removeListener(l, m[x].fn, void 0, !0), y) {
case 1:
m[x].fn.call(m[x].context);
break;
case 2:
m[x].fn.call(m[x].context, h);
break;
case 3:
m[x].fn.call(m[x].context, h, u);
break;
case 4:
m[x].fn.call(m[x].context, h, u, d);
break;
default:
if (!b)
for (w = 1, b = new Array(y - 1); w < y; w++)
b[w - 1] = arguments[w];
m[x].fn.apply(m[x].context, b);
}
}
return !0;
}, a.prototype.on = function(l, h, u) {
return o(this, l, h, u, !1);
}, a.prototype.once = function(l, h, u) {
return o(this, l, h, u, !0);
}, a.prototype.removeListener = function(l, h, u, d) {
var f = e ? e + l : l;
if (!this._events[f])
return this;
if (!h)
return r(this, f), this;
var g = this._events[f];
if (g.fn)
g.fn === h && (!d || g.once) && (!u || g.context === u) && r(this, f);
else {
for (var p = 0, m = [], y = g.length; p < y; p++)
(g[p].fn !== h || d && !g[p].once || u && g[p].context !== u) && m.push(g[p]);
m.length ? this._events[f] = m.length === 1 ? m[0] : m : r(this, f);
}
return this;
}, a.prototype.removeAllListeners = function(l) {
var h;
return l ? (h = e ? e + l : l, this._events[h] && r(this, h)) : (this._events = new i(), this._eventsCount = 0), this;
}, a.prototype.off = a.prototype.removeListener, a.prototype.addListener = a.prototype.on, a.prefixed = e, a.EventEmitter = a, s.exports = a;
})(Us);
var Jo = Us.exports;
const et = /* @__PURE__ */ Zo(Jo);
let Le;
const tr = new Uint8Array(16);
function er() {
if (!Le && (Le = typeof crypto < "u" && crypto.getRandomValues && crypto.getRandomValues.bind(crypto), !Le))
throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
return Le(tr);
}
const G = [];
for (let s = 0; s < 256; ++s)
G.push((s + 256).toString(16).slice(1));
function ir(s, t = 0) {
return G[s[t + 0]] + G[s[t + 1]] + G[s[t + 2]] + G[s[t + 3]] + "-" + G[s[t + 4]] + G[s[t + 5]] + "-" + G[s[t + 6]] + G[s[t + 7]] + "-" + G[s[t + 8]] + G[s[t + 9]] + "-" + G[s[t + 10]] + G[s[t + 11]] + G[s[t + 12]] + G[s[t + 13]] + G[s[t + 14]] + G[s[t + 15]];
}
const nr = typeof crypto < "u" && crypto.randomUUID && crypto.randomUUID.bind(crypto), Sn = {
randomUUID: nr
};
function sr(s, t, e) {
if (Sn.randomUUID && !t && !s)
return Sn.randomUUID();
s = s || {};
const i = s.random || (s.rng || er)();
if (i[6] = i[6] & 15 | 64, i[8] = i[8] & 63 | 128, t) {
e = e || 0;
for (let n = 0; n < 16; ++n)
t[e + n] = i[n];
return t;
}
return ir(i);
}
class qs extends et {
constructor(t = sr(), e = {}, i = { x: 0, y: 0 }) {
super(), this.state = "active", this.id = t, this.properties = new Map(Object.entries(e)), this._position = i, this.createdAt = Date.now(), this.lastUpdated = this.createdAt, this.validateInitialState(), this.emitLifecycleEvent("agentCreated");
}
/**
* Get agent property with type safety
*/
getProperty(t) {
return this.properties.get(t);
}
/**
* Set agent property with validation and event emission
*/
setProperty(t, e) {
this.validateProperty(t, e);
const i = this.properties.get(t);
this.properties.set(t, e), this.lastUpdated = Date.now(), this.emitPropertyChanged(t, i ?? null, e);
}
/**
* Get all agent properties as an object
*/
getProperties() {
return Object.fromEntries(this.properties.entries());
}
/**
* Get all properties as readonly record
*/
getAllProperties() {
return Object.fromEntries(this.properties.entries());
}
/**
* Check if agent has a specific property
*/
hasProperty(t) {
return this.properties.has(t);
}
/**
* Remove a property from the agent
*/
removeProperty(t) {
const e = this.properties.has(t);
if (e) {
const i = this.properties.get(t);
this.properties.delete(t), this.lastUpdated = Date.now(), this.emitPropertyChanged(t, i ?? null, null);
}
return e;
}
/**
* Get current position
*/
get position() {
return this._position;
}
/**
* Get current position (method form for compatibility)
*/
getPosition() {
return this._position;
}
/**
* Set position with validation and event emission
*/
setPosition(t) {
this.validatePosition(t);
const e = this._position;
this._position = t, this.lastUpdated = Date.now(), this.emitPositionChanged(e, t);
}
/**
* Translate position by offset
*/
translate(t, e) {
const i = {
x: this._position.x + t,
y: this._position.y + e
};
this.setPosition(i);
}
/**
* Get current agent state
*/
get currentState() {
return this.state;
}
/**
* Activate agent (make it active in simulation)
*/
activate() {
this.state !== "active" && (this.state = "active", this.emitLifecycleEvent("agentActivated"));
}
/**
* Deactivate agent (remove from simulation but keep in memory)
*/
deactivate() {
this.state === "active" && (this.state = "dormant", this.emitLifecycleEvent("agentDeactivated"));
}
/**
* Destroy agent (mark for removal from simulation)
*/
destroy() {
this.state !== "destroyed" && (this.state = "destroyed", this.emitLifecycleEvent("agentDestroyed"), this.removeAllListeners());
}
/**
* Check if agent is active
*/
isActive() {
return this.state === "active";
}
/**
* Check if agent is destroyed
*/
isDestroyed() {
return this.state === "destroyed";
}
/**
* Serialize agent to JSON for persistence
*/
toJSON() {
return {
id: this.id,
state: this.state,
position: this._position,
properties: Object.fromEntries(this.properties.entries()),
createdAt: this.createdAt,
lastUpdated: this.lastUpdated
};
}
/**
* Get string representation of agent
*/
toString() {
return `Agent(${this.id}, ${this.state}, ${this._position.x}, ${this._position.y})`;
}
/**
* Validate property value before setting
* Override in subclasses for custom validation
*/
validateProperty(t, e) {
if (t === "" || t === null)
throw new Error("Property key cannot be empty or null");
if (e !== null && typeof e == "object" && !Array.isArray(e))
try {
JSON.stringify(e);
} catch {
throw new Error("Property value must be JSON serializable");
}
}
/**
* Validate position before setting
* Override in subclasses for custom validation
*/
validatePosition(t) {
if (!isFinite(t.x) || !isFinite(t.y))
throw new Error("Position coordinates must be finite numbers");
}
/**
* Validate initial agent state
*/
validateInitialState() {
if (!this.id || this.id.length === 0)
throw new Error("Agent ID cannot be empty");
}
/**
* Emit property changed event
*/
emitPropertyChanged(t, e, i) {
const n = {
type: "propertyChanged",
timestamp: Date.now(),
agent: this,
property: t,
oldValue: e,
newValue: i
};
this.emit("propertyChanged", n);
}
/**
* Emit position changed event
*/
emitPositionChanged(t, e) {
const i = {
type: "positionChanged",
timestamp: Date.now(),
agent: this,
oldPosition: t,
newPosition: e
};
this.emit("positionChanged", i);
}
/**
* Emit lifecycle event
*/
emitLifecycleEvent(t) {
const e = {
type: t,
timestamp: Date.now(),
agent: this
};
this.emit(t, e);
}
}
class ai extends qs {
constructor(t, e = {}, i = { x: 0, y: 0 }) {
super(t, e, i);
}
/**
* Basic step implementation - override for custom behavior
* By default, does nothing (static agent)
*/
step() {
}
/**
* Simple position update with validation
*/
moveTo(t) {
this.setPosition(t);
}
/**
* Move relative to current position
*/
moveBy(t, e) {
this.translate(t, e);
}
/**
* Set agent energy level (common property)
*/
setEnergy(t) {
if (t < 0)
throw new Error("Energy cannot be negative");
this.setProperty("energy", t);
}
/**
* Get agent energy level
*/
getEnergy() {
return this.getProperty("energy") ?? 100;
}
/**
* Set agent activity level (0-1)
*/
setActivity(t) {
if (t < 0 || t > 1)
throw new Error("Activity must be between 0 and 1");
this.setProperty("activity", t);
}
/**
* Get agent activity level
*/
getActivity() {
return this.getProperty("activity") ?? 0.5;
}
/**
* Check if agent is at a specific position
*/
isAt(t) {
return this.position.x === t.x && this.position.y === t.y;
}
/**
* Calculate distance to another position
*/
distanceTo(t) {
const e = this.position.x - t.x, i = this.position.y - t.y;
return Math.sqrt(e * e + i * i);
}
/**
* Calculate distance to another agent
*/
distanceToAgent(t) {
return this.distanceTo(t.position);
}
/**
* Check if agent is within a certain distance of a position
*/
isNear(t, e) {
return this.distanceTo(t) <= e;
}
/**
* Check if agent is within a certain distance of another agent
*/
isNearAgent(t, e) {
return this.distanceToAgent(t) <= e;
}
}
class or extends ai {
constructor(t, e = {}, i = { x: 0, y: 0 }, n = {}) {
super(t, e, i), this.velocity = { vx: 0, vy: 0 }, this.previousPosition = i, e.x !== void 0 && (i = { ...i, x: e.x }), e.y !== void 0 && (i = { ...i, y: e.y }), this.setProperty("x", i.x), this.setProperty("y", i.y), this.movementConfig = {
maxSpeed: 5,
acceleration: 1,
friction: 0.95,
bounceOnBoundary: !0,
...n
};
}
/**
* Update agent position based on velocity
*/
step() {
this.previousPosition = this.position;
const t = this.getProperty("velocityX"), e = this.getProperty("velocityY");
t !== void 0 && e !== void 0 && (this.velocity = { vx: t, vy: e }), this.velocity = this.applyFriction(this.velocity), this.velocity = this.limitSpeed(this.velocity);
const i = {
x: this.position.x + this.velocity.vx,
y: this.position.y + this.velocity.vy
};
this.setPosition(i), this.setProperty("x", i.x), this.setProperty("y", i.y);
}
/**
* Set velocity directly
*/
setVelocity(t, e) {
this.velocity = { vx: t, vy: e };
}
/**
* Get current velocity
*/
getVelocity() {
return { ...this.velocity };
}
/**
* Add force to velocity (acceleration)
*/
addForce(t, e) {
const i = this.movementConfig.acceleration;
this.velocity = {
vx: this.velocity.vx + t * i,
vy: this.velocity.vy + e * i
};
}
/**
* Apply impulse (instant velocity change)
*/
applyImpulse(t, e) {
this.velocity = {
vx: this.velocity.vx + t,
vy: this.velocity.vy + e
};
}
/**
* Stop agent movement
*/
stop() {
this.velocity = { vx: 0, vy: 0 };
}
/**
* Set target speed in current direction
*/
setSpeed(t) {
const e = this.getSpeed();
if (e > 0) {
const i = t / e;
this.velocity = {
vx: this.velocity.vx * i,
vy: this.velocity.vy * i
};
}
}
/**
* Get current speed (magnitude of velocity)
*/
getSpeed() {
return Math.sqrt(
this.velocity.vx * this.velocity.vx + this.velocity.vy * this.velocity.vy
);
}
/**
* Get movement direction in radians
*/
getDirection() {
return Math.atan2(this.velocity.vy, this.velocity.vx);
}
/**
* Move towards a target position
*/
moveToward(t, e = 1) {
const i = t.x - this.position.x, n = t.y - this.position.y, o = Math.sqrt(i * i + n * n);
if (o > 0) {
const r = i / o * e, a = n / o * e;
this.addForce(r, a);
}
}
/**
* Move away from a position
*/
moveAway(t, e = 1) {
const i = this.position.x - t.x, n = this.position.y - t.y, o = Math.sqrt(i * i + n * n);
if (o > 0) {
const r = i / o * e, a = n / o * e;
this.addForce(r, a);
}
}
/**
* Apply random movement (wandering behavior)
*/
wander(t = 0.5) {
const e = Math.random() * 2 * Math.PI, i = Math.cos(e) * t, n = Math.sin(e) * t;
this.addForce(i, n);
}
/**
* Get movement configuration
*/
getMovementConfig() {
return { ...this.movementConfig };
}
/**
* Update movement configuration
*/
updateMovementConfig(t) {
this.movementConfig = { ...this.movementConfig, ...t };
}
/**
* Check if agent is moving
*/
isMoving() {
return this.getSpeed() > 1e-3;
}
/**
* Handle boundary collision with environment
*/
handleBoundaryCollision(t) {
let { vx: e, vy: i } = this.velocity;
(this.position.x <= 0 || this.position.x >= t.width) && (this.movementConfig.bounceOnBoundary ? e = -e * 0.8 : e = 0), (this.position.y <= 0 || this.position.y >= t.height) && (this.movementConfig.bounceOnBoundary ? i = -i * 0.8 : i = 0), this.velocity = { vx: e, vy: i };
}
/**
* Apply friction to velocity
*/
applyFriction(t) {
const e = this.movementConfig.friction;
return {
vx: t.vx * e,
vy: t.vy * e
};
}
/**
* Limit velocity to maximum speed
*/
limitSpeed(t) {
const e = Math.sqrt(
t.vx * t.vx + t.vy * t.vy
), i = this.movementConfig.maxSpeed;
if (e > i) {
const n = i / e;
return {
vx: t.vx * n,
vy: t.vy * n
};
}
return t;
}
}
class Zt extends ai {
constructor(t, e = {}, i = { x: 0, y: 0 }) {
super(t, e, i), this.connections = /* @__PURE__ */ new Map(), this.incomingConnections = /* @__PURE__ */ new Set(), this.influence = 1, this.trustLevels = /* @__PURE__ */ new Map();
}
/**
* Basic step - can be overridden for network-specific behaviors
*/
step() {
this.decayConnections(), this.updateInfluence();
}
/**
* Create connection to another agent
*/
connect(t, e = "default", i = 1, n = {}) {
if (t.id === this.id)
throw new Error("Agent cannot connect to itself");
if (i < 0 || i > 1)
throw new Error("Connection strength must be between 0 and 1");
const o = {
target: t,
type: e,
strength: i,
createdAt: Date.now(),
lastInteraction: Date.now(),
metadata: { ...n }
};
this.connections.set(t.id, o), t instanceof Zt && t.addIncomingConnection(this.id), this.emitConnectionEvent("connectionFormed", t, e, i);
}
/**
* Remove connection to another agent
*/
disconnect(t) {
const e = this.connections.has(t.id);
if (e) {
const i = this.connections.get(t.id);
this.connections.delete(t.id), t instanceof Zt && t.removeIncomingConnection(this.id), this.emitConnectionEvent(
"connectionBroken",
t,
i.type,
i.strength
);
}
return e;
}
/**
* Check if connected to another agent
*/
isConnectedTo(t) {
return this.connections.has(t.id);
}
/**
* Get connection to specific agent
*/
getConnection(t) {
return this.connections.get(t.id);
}
/**
* Get all connections
*/
getAllConnections() {
return Array.from(this.connections.values());
}
/**
* Get connections of specific type
*/
getConnectionsByType(t) {
return Array.from(this.connections.values()).filter(
(e) => e.type === t
);
}
/**
* Get connection count
*/
getConnectionCount() {
return this.connections.size;
}
/**
* Get strong connections (strength > 0.7)
*/
getStrongConnections() {
return Array.from(this.connections.values()).filter(
(t) => t.strength > 0.7
);
}
/**
* Get weak connections (strength <= 0.3)
*/
getWeakConnections() {
return Array.from(this.connections.values()).filter(
(t) => t.strength <= 0.3
);
}
/**
* Update connection strength
*/
updateConnectionStrength(t, e) {
if (e < 0 || e > 1)
throw new Error("Connection strength must be between 0 and 1");
const i = this.connections.get(t.id);
if (!i)
throw new Error(`No connection to agent ${t.id}`);
const n = {
...i,
strength: e,
lastInteraction: Date.now()
};
this.connections.set(t.id, n), this.emitConnectionEvent(
"connectionModified",
t,
i.type,
e
);
}
/**
* Strengthen connection through interaction
*/
strengthenConnection(t, e = 0.1) {
const i = this.connections.get(t.id);
if (i) {
const n = Math.min(1, i.strength + e);
this.updateConnectionStrength(t, n);
}
}
/**
* Weaken connection
*/
weakenConnection(t, e = 0.1) {
const i = this.connections.get(t.id);
if (i) {
const n = Math.max(0, i.strength - e);
n === 0 ? this.disconnect(t) : this.updateConnectionStrength(t, n);
}
}
/**
* Set trust level for another agent
*/
setTrust(t, e) {
if (e < 0 || e > 1)
throw new Error("Trust level must be between 0 and 1");
this.trustLevels.set(t.id, e);
}
/**
* Get trust level for another agent
*/
getTrust(t) {
return this.trustLevels.get(t.id) ?? 0.5;
}
/**
* Get network influence
*/
getInfluence() {
return this.influence;
}
/**
* Set network influence
*/
setInfluence(t) {
if (t < 0)
throw new Error("Influence cannot be negative");
this.influence = t;
}
/**
* Get network neighbors (connected agents)
*/
getNeighbors() {
return Array.from(this.connections.values()).map((t) => t.target);
}
/**
* Get neighbors within a certain trust threshold
*/
getTrustedNeighbors(t = 0.7) {
return this.getNeighbors().filter(
(e) => this.getTrust(e) >= t
);
}
/**
* Calculate network statistics
*/
getNetworkStats() {
const t = Array.from(this.connections.values()), e = t.filter((r) => r.strength > 0.7), i = t.filter((r) => r.strength <= 0.3), n = t.length > 0 ? t.reduce((r, a) => r + a.strength, 0) / t.length : 0, o = this.calculateClusteringCoefficient();
return {
connectionCount: t.length,
strongConnections: e.length,
weakConnections: i.length,
averageStrength: n,
mostConnectedAgent: this.findMostConnectedNeighbor(),
clusteringCoefficient: o
};
}
/**
* Add incoming connection reference
*/
addIncomingConnection(t) {
this.incomingConnections.add(t);
}
/**
* Remove incoming connection reference
*/
removeIncomingConnection(t) {
this.incomingConnections.delete(t);
}
/**
* Get incoming connection count
*/
getIncomingConnectionCount() {
return this.incomingConnections.size;
}
/**
* Calculate degree centrality (total connections)
*/
getDegreeCentrality() {
return this.connections.size + this.incomingConnections.size;
}
/**
* Decay connection strengths over time
*/
decayConnections() {
const e = Date.now(), i = 24 * 60 * 60 * 1e3;
for (const [n, o] of this.connections.entries()) {
const r = e - o.lastInteraction;
if (r > i) {
const a = Math.min(1e-3 * r / i, 0.1), c = Math.max(0, o.strength - a);
if (c === 0)
this.connections.delete(n), this.emitConnectionEvent(
"connectionBroken",
o.target,
o.type,
0
);
else {
const l = {
...o,
strength: c
};
this.connections.set(n, l);
}
}
}
}
/**
* Update influence based on network position
*/
updateInfluence() {
const t = Array.from(this.connections.values()).reduce(
(i, n) => i + n.strength,
0
), e = this.incomingConnections.size * 0.5;
this.influence = Math.max(
0.1,
1 + t * 0.1 + e * 0.1
);
}
/**
* Calculate clustering coefficient
*/
calculateClusteringCoefficient() {
const t = this.getNeighbors();
if (t.length < 2)
return 0;
let e = 0, i = 0;
for (let n = 0; n < t.length; n++)
for (let o = n + 1; o < t.length; o++) {
i++;
const r = t[n], a = t[o];
r instanceof Zt && a && r.isConnectedTo(a) && e++;
}
return i > 0 ? e / i : 0;
}
/**
* Find the most connected neighbor
*/
findMostConnectedNeighbor() {
let t = -1, e = null;
for (const i of this.getNeighbors())
if (i instanceof Zt) {
const n = i.getConnectionCount();
n > t && (t = n, e = i.id);
}
return e;
}
/**
* Emit connection event
*/
emitConnectionEvent(t, e, i, n) {
const o = {
type: t,
timestamp: Date.now(),
source: this,
target: e,
connectionType: i,
strength: n
};
this.emit(t, o);
}
}
class Gs extends et {
constructor(t) {
super(), this.validateDimensions(t), this.dimensions = { ...t }, this.agents = /* @__PURE__ */ new Set(), this.agentPositions = /* @__PURE__ */ new Map();
}
/**
* Add agent to environment at specified position
*/
addAgent(t, e) {
if (this.agents.has(t))
throw new Error(`Agent ${t.id} is already in this environment`);
const i = e ?? t.position;
this.validatePosition(i), this.agents.add(t), this.agentPositions.set(t, i), e && t.setPosition(i), this.onAgentAdded(t, i), this.emit("agentAdded", { agent: t, position: i });
}
/**
* Remove agent from environment
*/
removeAgent(t) {
return this.agents.has(t) ? (this.agents.delete(t), this.agentPositions.delete(t), this.onAgentRemoved(t), this.emit("agentRemoved", { agent: t }), !0) : !1;
}
/**
* Move agent to new position within environment
*/
moveAgent(t, e) {
if (!this.agents.has(t))
throw new Error(`Agent ${t.id} is not in this environment`);
const i = this.applyBoundaryConditions(e), n = this.agentPositions.get(t);
this.agentPositions.set(t, i), t.setPosition(i), this.onAgentMoved(t, n, i), this.emit("agentMoved", {
agent: t,
oldPosition: n,
newPosition: i
});
}
/**
* Get agent's current position in environment
*/
getAgentPosition(t) {
return this.agentPositions.get(t);
}
/**
* Get all agents in environment
*/
getAllAgents() {
return Array.from(this.agents);
}
/**
* Get number of agents in environment
*/
getAgentCount() {
return this.agents.size;
}
/**
* Check if position is within environment bounds
*/
isValidPosition(t) {
return t.x >= 0 && t.x <= this.dimensions.width && t.y >= 0 && t.y <= this.dimensions.height;
}
/**
* Apply boundary conditions to position
*/
applyBoundaryConditions(t) {
switch (this.dimensions.boundaryType) {
case "periodic":
return this.applyPeriodicBoundary(t);
case "reflective":
return this.applyReflectiveBoundary(t);
case "absorbing":
return this.applyAbsorbingBoundary(t);
default:
throw new Error(
`Unknown boundary type: ${this.dimensions.boundaryType}`
);
}
}
/**
* Calculate distance between two positions
*/
distance(t, e) {
const i = t.x - e.x, n = t.y - e.y;
return Math.sqrt(i * i + n * n);
}
/**
* Get environment dimensions
*/
getDimensions() {
return { ...this.dimensions };
}
/**
* Hook for subclasses when agent is added
*/
onAgentAdded(t, e) {
}
/**
* Hook for subclasses when agent is removed
*/
onAgentRemoved(t) {
}
/**
* Hook for subclasses when agent is moved
*/
onAgentMoved(t, e, i) {
}
/**
* Validate environment dimensions
*/
validateDimensions(t) {
if (t.width <= 0 || t.height <= 0)
throw new Error("Environment dimensions must be positive");
if (!isFinite(t.width) || !isFinite(t.height))
throw new Error("Environment dimensions must be finite");
}
/**
* Validate position coordinates
*/
validatePosition(t) {
if (!isFinite(t.x) || !isFinite(t.y))
throw new Error("Position coordinates must be finite numbers");
}
/**
* Apply periodic boundary conditions (wrap around)
*/
applyPeriodicBoundary(t) {
const e = (t.x % this.dimensions.width + this.dimensions.width) % this.dimensions.width, i = (t.y % this.dimensions.height + this.dimensions.height) % this.dimensions.height;
return { x: e, y: i };
}
/**
* Apply reflective boundary conditions (bounce back)
*/
applyReflectiveBoundary(t) {
let e = t.x, i = t.y;
return e < 0 && (e = -e), e > this.dimensions.width && (e = 2 * this.dimensions.width - e), i < 0 && (i = -i), i > this.dimensions.height && (i = 2 * this.dimensions.height - i), { x: e, y: i };
}
/**
* Apply absorbing boundary conditions (clamp to bounds)
*/
applyAbsorbingBoundary(t) {
const e = Math.max(0, Math.min(this.dimensions.width, t.x)), i = Math.max(0, Math.min(this.dimensions.height, t.y));
return { x: e, y: i };
}
}
class rr extends Gs {
constructor(t, e) {
let i;
typeof t == "number" && e !== void 0 ? i = {
width: t,
height: e,
boundaryType: "absorbing",
enableSpatialIndex: !0,
maxObjectsPerNode: 10,
maxTreeDepth: 6
} : i = t, super(i), this.config = { ...i }, this.quadtree = null, this.distanceFunction = (n, o) => {
const r = n.x - o.x, a = n.y - o.y;
return Math.sqrt(r * r + a * a);
}, this.initializeQuadtree();
}
/**
* Find agents within radius of position
*/
findNeighbors(t, e, i = {}) {
const n = performance.now(), o = i.maxResults ?? Number.MAX_SAFE_INTEGER, r = i.includeDistance ?? !1, a = this.config.enableSpatialIndex && this.quadtree ? this.queryQuadtree(t, e) : Array.from(this.agents), c = [], l = [];
for (const h of a) {
if (c.length >= o)
break;
const u = this.agentPositions.get(h);
if (!u)
continue;
const d = this.distanceFunction(t, u);
if (d <= e) {
if (i.filterFn && !i.filterFn(h))
continue;
c.push(h), r && l.push(d);
}
}
if (r && l.length > 0) {
const h = c.map((u, d) => ({
agent: u,
distance: l[d] ?? 0
}));
h.sort((u, d) => u.distance - d.distance), c.length = 0, l.length = 0;
for (const u of h)
c.push(u.agent), l.push(u.distance);
}
return {
items: c,
distances: r ? l : [],
queryTime: performance.now() - n
};
}
/**
* Get agents at specific position (within small tolerance)
*/
getAgentsAt(t) {
return this.findNeighbors(t, 1e-3).items;
}
/**
* Set custom distance function
*/
setDistanceFunction(t) {
this.distanceFunction = t;
}
/**
* Get Manhattan distance function
*/
static getManhattanDistance() {
return (t, e) => Math.abs(t.x - e.x) + Math.abs(t.y - e.y);
}
/**
* Get Euclidean distance function (default)
*/
static getEuclideanDistance() {
return (t, e) => {
const i = t.x - e.x, n = t.y - e.y;
return Math.sqrt(i * i + n * n);
};
}
/**
* Get Chebyshev distance function (max of x,y differences)
*/
static getChebyshevDistance() {
return (t, e) => Math.max(Math.abs(t.x - e.x), Math.abs(t.y - e.y));
}
/**
* Get current configuration
*/
getConfig() {
return { ...this.config };
}
/**
* Update spatial configuration
*/
updateConfig(t) {
Object.assign(this.config, t), ("enableSpatialIndex" in t || "maxObjectsPerNode" in t || "maxTreeDepth" in t) && this.rebuildQuadtree();
}
/**
* Get quadtree statistics
*/
getQuadtreeStats() {
return this.quadtree ? this.calculateQuadtreeStats(this.quadtree) : { nodeCount: 0, maxDepth: 0, agentCount: 0 };
}
/**
* Force rebuild of spatial index
*/
rebuildQuadtree() {
if (this.config.enableSpatialIndex) {
this.initializeQuadtree();
for (const [t, e] of this.agentPositions.entries())
this.insertIntoQuadtree(t, e);
}
}
/**
* Check if quadtree needs rebalancing
*/
needsRebalancing() {
if (!this.quadtree || !this.config.enableSpatialIndex)
return !1;
const t = this.getQuadtreeStats(), e = t.agentCount / t.nodeCount;
return t.maxDepth > this.config.maxTreeDepth * 1.5 || e < this.config.maxObjectsPerNode * 0.2;
}
/**
* Rebalance quadtree for optimal performance
*/
rebalanceQuadtree() {
if (!this.needsRebalancing())
return;
const t = [];
for (const [i, n] of this.agentPositions.entries())
t.push({ agent: i, position: n });
this.initializeQuadtree();
const e = this.sortByMortonCode(t);
for (const { agent: i, position: n } of e)
this.insertIntoQuadtree(i, n);
}
/**
* Sort agents by Morton code (Z-order) for better spatial locality
*/
sortByMortonCode(t) {
return t.sort((e, i) => {
const n = this.calculateMortonCode(e.position), o = this.calculateMortonCode(i.position);
return n - o;
});
}
/**
* Calculate Morton code (Z-order) for a position
*/
calculateMortonCode(t) {
const e = Math.floor(t.x / this.dimensions.width * 65535), i = Math.floor(t.y / this.dimensions.height * 65535);
let n = 0;
for (let o = 0; o < 16; o++)
n |= (e & 1 << o) << o | (i & 1 << o) << o + 1;
return n;
}
/**
* Merge quadtree nodes if they're underutilized
*/
tryMergeNode(t) {
if (!t.children)
return !1;
let e = 0;
for (const i of t.children) {
if (i.children)
return !1;
e += i.agents.length;
}
if (e <= this.config.maxObjectsPerNode) {
t.agents = [];
for (const i of t.children)
t.agents.push(...i.agents);
return t.children = null, !0;
}
return !1;
}
/**
* Optimize quadtree by merging underutilized nodes
*/
optimizeQuadtree() {
!this.quadtree || !this.config.enableSpatialIndex || this.optimizeNode(this.quadtree);
}
/**
* Recursively optimize quadtree nodes
*/
optimizeNode(t) {
if (t.children) {
for (const e of t.children)
this.optimizeNode(e);
this.tryMergeNode(t);
}
}
/**
* Hook: Handle agent addition
*/
onAgentAdded(t, e) {
this.config.enableSpatialIndex && this.quadtree && this.insertIntoQuadtree(t, e);
}
/**
* Hook: Handle agent removal
*/
onAgentRemoved(t) {
this.config.enableSpatialIndex && this.quadtree && this.removeFromQuadtree(t);
}
/**
* Hook: Handle agent movement
*/
onAgentMoved(t, e, i) {
this.config.enableSpatialIndex && this.quadtree && (this.removeFromQuadtree(t), this.insertIntoQuadtree(t, i));
}
/**
* Initialize quadtree structure
*/
initializeQuadtree() {
if (!this.config.enableSpatialIndex) {
this.quadtree = null;
return;
}
this.quadtree = {
bounds: {
x: 0,
y: 0,
width: this.dimensions.width,
height: this.dimensions.height
},
agents: [],
children: null,
level: 0
};
}
/**
* Insert agent into quadtree
*/
insertIntoQuadtree(t, e) {
this.quadtree && this.insertIntoNode(this.quadtree, t, e);
}
/**
* Remove agent from quadtree
*/
removeFromQuadtree(t) {
this.quadtree && this.removeFromNode(this.quadtree, t);
}
/**
* Insert agent into specific quadtree node
*/
insertIntoNode(t, e, i) {
if (this.pointInBounds(i, t.bounds)) {
if (t.children) {
for (const n of t.children)
this.insertIntoNode(n, e, i);
return;
}
t.agents.push(e), t.agents.length > this.config.maxObjectsPerNode && t.level < this.config.maxTreeDepth && this.splitNode(t);
}
}
/**
* Remove agent from quadtree node
*/
removeFromNode(t, e) {
const i = t.agents.indexOf(e);
if (i >= 0)
return t.agents.splice(i, 1), !0;
if (t.children) {
for (const n of t.children)
if (this.removeFromNode(n, e))
return !0;
}
return !1;
}
/**
* Split quadtree node into four children
*/
splitNode(t) {
const { x: e, y: i, width: n, height: o } = t.bounds, r = n / 2, a = o / 2;
t.children = [
// Top-left
{
bounds: { x: e, y: i, width: r, height: a },
agents: [],
children: null,
level: t.level + 1
},
// Top-right
{
bounds: { x: e + r, y: i, width: r, height: a },
agents: [],
children: null,
level: t.level + 1
},
// Bottom-left
{
bounds: { x: e, y: i + a, width: r, height: a },
agents: [],
children: null,
level: t.level + 1
},
// Bottom-right
{
bounds: {
x: e + r,
y: i + a,
width: r,
height: a
},
agents: [],
children: null,
level: t.level + 1
}
];
for (const c of t.agents) {
const l = this.agentPositions.get(c);
if (l) {
for (const h of t.children)
if (this.pointInBounds(l, h.bounds)) {
this.insertIntoNode(h, c, l);
break;
}
}
}
t.agents = [];
}
/**
* Query quadtree for agents within radius
*/
queryQuadtree(t, e) {
if (!this.quadtree)
return [];
const i = [];
return this.queryNode(this.quadtree, t, e, i), i;
}
/**
* Query specific quadtree node
*/
queryNode(t, e, i, n) {
if (this.circleIntersectsBounds(e, i, t.bounds) && (n.push(...t.agents), t.children))
for (const o of t.children)
this.queryNode(o, e, i, n);
}
/**
* Check if point is within bounds
*/
pointInBounds(t, e) {
return t.x >= e.x && t.x < e.x + e.width && t.y >= e.y && t.y < e.y + e.height;
}
/**
* Check if circle intersects with bounds
*/
circleIntersectsBounds(t, e, i) {
const n = Math.max(
i.x,
Math.min(t.x, i.x + i.width)
), o = Math.max(
i.y,
Math.min(t.y, i.y + i.height)
), r = t.x - n, a = t.y - o;
return r * r + a * a <= e * e;
}
/**
* Calculate quadtree statistics
*/
calculateQuadtreeStats(t) {
let e = 1, i = t.level, n = t.agents.length;
if (t.children)
for (const o of t.children) {
const r = this.calculateQuadtreeStats(o);
e += r.nodeCount, i = Math.max(i, r.maxDepth), n += r.agentCount;
}
return { nodeCount: e, maxDepth: i, agentCount: n };
}
}
class Tu extends Gs {
constructor(t, e, i) {
let n;
if (typeof t == "number" && e !== void 0) {
const o = t, r = i || 1;
n = {
width: e * r,
height: o * r,
boundaryType: "absorbing",
rows: o,
cols: e,
neighborhoodType: "moore",
allowMultipleOccupancy: !0
};
} else
n = t;
super(n), this.config = { ...n }, this.agentCoordinates = /* @__PURE__ */ new Map(), this.grid = this.initializeGrid(), this.validateConfiguration();
}
/**
* Find neighbors within radius (in grid cells)
*/
findNeighbors(t, e, i = {}) {
const n = performance.now(), o = i.maxResults ?? Number.MAX_SAFE_INTEGER, r = this.positionToGrid(t);
if (!this.isValidCoordinate(r))
return {
items: [],
distances: [],
queryTime: performance.now() - n
};
const a = [], c = [], l = Math.floor(e);
for (let h = -l; h <= l; h++)
for (let u = -l; u <= l && !(a.length >= o); u++) {
const d = {
row: r.row + h,
col: r.col + u
};
if (!this.isValidCoordinate(d))
continue;
const f = this.gridDistance(r, d);
if (f > e)
continue;
const g = this.grid[d.row]?.[d.col];
if (g)
for (const p of g.agents) {
if (a.length >= o)
break;
i.filterFn && !i.filterFn(p) || (a.push(p), i.includeDistance && c.push(f));
}
}
if (i.includeDistance && c.length > 0) {
const h = a.map((u, d) => ({
agent: u,
distance: c[d] ?? 0
}));
h.sort((u, d) => u.distance - d.distance), a.length = 0, c.length = 0;
for (const u of h)
a.push(u.agent), c.push(u.distance);
}
return {
items: a,
distances: i.includeDistance ? c : [],
queryTime: performance.now() - n
};
}
/**
* Get agents at specific position
*/
getAgentsAt(t) {
const e = this.positionToGrid(t);
if (!this.isValidCoordinate(e))
return [];
const i = this.grid[e.row]?.[e.col];
return i ? Array.from(i.agents) : [];
}
/**
* Get agents in specific grid cell
*/
getAgentsAtCell(t) {
if (!this.isValidCoordinate(t))
return [];
const e = this.grid[t.row]?.[t.col];
return e ? Array.from(e.agents) : [];
}
/**
* Get grid coordinate for agent
*/
getAgentGridCoordinate(t) {
return this.agentCoordinates.get(t);
}
/**
* Get neighbors of a grid cell
*/
getCellNeighbors(t) {
const e = [];
if (this.config.neighborhoodType === "moore")
for (let i = -1; i <= 1; i++)
for (let n = -1; n <= 1; n++) {
if (i === 0 && n === 0)
continue;
const o = {
row: t.row + i,
col: t.col + n
};
this.isValidCoordinate(o) && e.push(o);
}
else {
const i = [
{ row: -1, col: 0 },
// North
{ row: 1, col: 0 },
// South
{ row: 0, col: -1 },
// West
{ row: 0, col: 1 }
// East
];
for (const n of i) {
const o = {
row: t.row + n.row,
col: t.col + n.col
};
this.isValidCoordinate(o) && e.push(o);
}
}
return e;
}
/**
* Check if cell can accommodate more agents
*/
canPlaceAgent(t) {
if (!this.isValidCoordinate(t))
return !1;
const e = this.grid[t.row]?.[t.col];
return e ? this.config.allowMultipleOccupancy ? e.agents.size < e.maxOccupancy : e.agents.size === 0 : !1;
}
/**
* Get empty cells in grid
*/
getEmptyCells() {
const t = [];
for (let e = 0; e < this.config.rows; e++)
for (let i = 0; i < this.config.cols; i++) {
const n = { row: e, col: i };
this.canPlaceAgent(n) && t.push(n);
}
return t;
}
/**
* Get grid occupancy statistics
*/
getOccupancyStats() {
let t = 0, e = 0, i = 0;
for (let o = 0; o < this.config.rows; o++)
for (let r = 0; r < this.config.cols; r++) {
const a = this.grid[o]?.[r];
if (!a)
continue;
const c = a.agents.size;
c > 0 && (t++, e += c, i = Math.max(i, c));
}
const n = this.config.rows * this.config.cols;
return {
totalCells: n,
occupiedCells: t,
emptyCells: n - t,
averageOccupancy: t > 0 ? e / t : 0,
maxOccupancy: i
};
}
/**
* Convert position to grid coordinate
*/
positionToGrid(t) {
const e = this.dimensions.width / this.config.cols, i = this.dimensions.height / this.config.rows;
return {
row: Math.floor(t.y / i),
col: Math.floor(t.x / e)
};
}
/**
* Convert grid coordinate to position (center of cell)
*/
gridToPosition(t) {
const e = this.dimensions.width / this.config.cols, i = this.dimensions.height / this.config.rows;
return {
x: (t.col + 0.5) * e,
y: (t.row + 0.5) * i
};
}
/**
* Calculate distance between grid coordinates
*/
gridDistance(t, e) {
return this.config.neighborhoodType === "moore" ? Math.max(Math.abs(t.row - e.row), Math.abs(t.col - e.col)) : Math.abs(t.row - e.row) + Math.abs(t.col - e.col);
}
/**
* Get current grid configuration
*/
getGridConfig() {
return { ...this.config };
}
/**
* Place agent at specific grid coordinate
*/
placeAgentAtCell(t, e) {
if (!this.canPlaceAgent(e))
return !1;
this.removeAgentFromGrid(t);
const i = this.grid[e.row]?.[e.col];
if (!i)
return !1;
i.agents.add(t), this.agentCoordinates.set(t, e);
const n = this.gridToPosition(e);
return t.setPosition(n), !0;
}
/**
* Hook: Handle agent addition
*/
onAgentAdded(t, e) {
const i = this.positionToGrid(e);
if (this.isValidCoordinate(i) && this.canPlaceAgent(i)) {
const n = this.grid[i.row]?.[i.col];
if (!n)
throw new Error(
`Invalid grid cell at ${i.row}, ${i.col}`
);
n.agents.add(t), this.agentCoordinates.set(t, i);
const o = this.gridToPosition(i);
t.setPosition(o);
} else
throw new Error(
`Cannot place agent at position ${e.x}, ${e.y} - cell occupied or invalid`
);
}
/**
* Hook: Handle agent removal
*/
onAgentRemoved(t) {
this.removeAgentFromGrid(t);
}
/**
* Hook: Handle agent movement
*/
onAgentMoved(t, e, i) {
const n = this.positionToGrid(i);
if (!this.isValidCoordinate(n))
throw new Error(
`Invalid grid position: ${n.row}, ${n.col}`
);
const o = this.agentCoordinates.get(t);
if (!o || o.row !== n.row || o.col !== n.col) {
if (!this.canPlaceAgent(n))
throw new Error(
`Cannot move agent to occupied cell: ${n.row}, ${n.col}`
);
if (o && this.isValidCoordinate(o)) {
const c = this.grid[o.row]?.[o.col];
c && c.agents.delete(t);
}
const r = this.grid[n.row]?.[n.col];
if (!r)
throw new Error(
`Invalid grid cell at ${n.row}, ${n.col}`
);
r.agents.add(t), this.agentCoordinates.set(t, n);
const a = this.gridToPosition(n);
t.setPosition(a);
}
}
/**
* Initialize grid structure
*/
initializeGrid() {
const t = [];
for (let e = 0; e < this.config.rows; e++) {
t[e] = [];
for (let i = 0; i < this.config.cols; i++)
t[e][i] = {
coordinate: { row: e, col: i },
agents: /* @__PURE__ */ new Set(),
maxOccupancy: this.config.allowMultipleOccupancy ? 10 : 1
// Default max occupancy
};
}
return t;
}
/**
* Check if grid coordinate is valid
*/
isValidCoordinate(t) {
return t.row >= 0 && t.row < this.config.rows && t.col >= 0 && t.col < this.config.cols;
}
/**
* Remove agent from grid
*/
removeAgentFromGrid(t) {
const e = this.agentCoordinates.get(t);
if (e && this.isValidCoordinate(e)) {
const i = this.grid[e.row]?.[e.col];
i && i.agents.delete(t);
}
this.agentCoordinates.delete(t);
}
/**
* Validate grid configuration
*/
validateConfiguration() {
if (this.config.rows <= 0 || this.config.cols <= 0)
throw new Error("Grid dimensions must be positive");
if (this.dimensions.width / this.config.cols < 1 || this.dimensions.height / this.config.rows < 1)
throw new Error("Grid cells are too small for given dimensions");
}
}
class Qs extends et {
constructor(t) {
super(), this.agents = /* @__PURE__ */ new Set(), this.stepNumber = 0, this.lastStepTime = 0, this.totalSteps = 0, this.randomSeed = t, this.randomSeed !== void 0 && this.initializeRandom(this.randomSeed);
}
/**
* Add agent to scheduling
*/
addAgent(t) {
if (this.agents.has(t))
throw new Error(`Agent ${t.id} is already scheduled`);
this.agents.add(t), this.onAgentAdded(t), this.emit("agentAdded", { agent: t, schedulerSize: this.agents.size });
}
/**
* Remove agent from scheduling
*/
removeAgent(t) {
return this.agents.has(t) ? (this.agents.delete(t), this.onAgentRemoved(t), this.emit("agentRemoved", { agent: t, schedulerSize: this.agents.size }), !0) : !1;
}
/**
* Get all scheduled agents
*/
getAgents() {
return Array.from(this.agents);
}
/**
* Get number of scheduled agents
*/
getAgentCount() {
return this.agents.size;
}
/**
* Execute one simulation step
*/
step() {
const t = performance.now(), i = this.getActivationOrder().filter((n) => n.isActive());
this.emit("stepStarted", {
stepNumber: this.stepNumber,
agentCount: i.length
});
for (const n of i)
try {
n.step();
} catch (o) {
this.emit("agentStepError", {
agent: n,
error: o,
stepNumber: this.stepNumber
}), console.warn(`Agent ${n.id} step failed:`, o);
}
this.stepNumber++, this.totalSteps++, this.lastStepTime = performance.now() - t, this.emit("stepCompleted", {
stepNumber: this.stepNumber,
executionTime: this.lastStepTime,
agentCount: i.length
});
}
/**
* Reset scheduler state
*/
reset() {
this.stepNumber = 0, this.totalSteps = 0, this.lastStepTime = 0, this.randomSeed !== void 0 && this.initializeRandom(this.randomSeed), this.emit("schedulerReset");
}
/**
* Get current step number
*/
getCurrentStep() {
return this.stepNumber;
}
/**
* Get total steps executed
*/
getTotalSteps() {
return this.totalSteps;
}
/**
* Get last step execution time in milliseconds
*/
getLastStepTime() {
return this.lastStepTime;
}
/**
* Get scheduling statistics
*/
getStatistics() {
const t = this.totalSteps > 0 ? this.lastStepTime / this.totalSteps : 0;
return {
totalAgents: this.agents.size,
activeAgents: Array.from(this.agents).filter((e) => e.isActive()).length,
currentStep: this.stepNumber,
totalSteps: this.totalSteps,
lastStepTime: this.lastStepTime,
averageStepTime: t,
schedulerType: this.getSchedulerType()
};
}
/**
* Hook for subclasses when agent is added
*/
onAgentAdded(t) {
}
/**
* Hook for subclasses when agent is removed
*/
onAgentRemoved(t) {
}
/**
* Initialize random number generator with seed
*/
initializeRandom(t) {
let e = t;
Math.random = () => (e = (e * 1664525 + 1013904223) % 4294967296, e / 4294967296);
}
}
class ar extends Qs {
constructor(t) {
super(), this.seed = t, this.rngState = t ?? Date.now();
}
/**
* Get agent activation order (implementing abstract method)
*/
getActivationOrder() {
return this.schedule(this.getAgents());
}
/**
* Get scheduler type (implementing abstract method)
*/
getSchedulerType() {
return this.getType();
}
/**
* Schedule agents in random order
*/
schedule(t) {
const e = t.filter((n) => n.isActive());
if (e.length === 0)
return [];
const i = [...e];
return this.shuffleArray(i), i;
}
/**
* Set random seed for reproducible results
*/
setSeed(t) {
this.seed = t, this.rngState = t;
}
/**
* Get current seed
*/
getSeed() {
return this.seed;
}
/**
* Reset RNG state to original seed
*/
resetSeed() {
this.rngState = this.seed ?? Date.now();
}
/**
* Get scheduler type
*/
getType() {
return "random";
}
/**
* Get scheduler configuration
*/
getConfiguration() {
return {
type: this.getType(),
seed: this.seed,
currentRngState: this.rngState,
repr