1use crate::{
33 agent::Agent,
34 interaction::{InteractionError, PositionedAgent, SpaceInteraction},
35 model::Model,
36 scheduler::Scheduler,
37 space::Space,
38 store::AgentStore,
39 types::{AgentId, Time},
40};
41use rand::RngCore;
42use tracing::{debug, trace};
43
44use std::cell::{Ref, RefCell, RefMut};
45use std::marker::PhantomData;
46
47pub trait HasAgentIds {
52 fn agent_ids(&self) -> Vec<AgentId>;
54
55 fn agent_ids_into(&self, buf: &mut Vec<AgentId>);
57}
58
59impl<S, A, Store, Props, R, Sch> StandardModel<S, A, Store, Props, R, Sch>
60where
61 A: PositionedAgent,
62 S: SpaceInteraction<A>,
63 Store: AgentStore<A>,
64 R: RngCore,
65 Sch: Scheduler<Self>,
66{
67 pub fn insert_positioned_agent(&mut self, agent: A) -> Result<(), InteractionError<S::Error>> {
69 crate::interaction::add_agent(self, agent)
70 }
71
72 pub fn remove_positioned_agent(
74 &mut self,
75 id: AgentId,
76 ) -> Result<Option<A>, InteractionError<S::Error>> {
77 crate::interaction::remove_agent(self, id)
78 }
79
80 pub fn move_positioned_agent(
82 &mut self,
83 id: AgentId,
84 new_position: A::Position,
85 ) -> Result<(), InteractionError<S::Error>> {
86 crate::interaction::move_agent(self, id, new_position)
87 }
88
89 pub fn validate_space_index(&self) -> Result<(), InteractionError<S::Error>> {
91 crate::interaction::validate_space_index(self)
92 }
93
94 pub fn step_spatial(&mut self) -> Result<(), InteractionError<S::Error>> {
97 let has_agent_step = self.agent_step_ctx.is_some();
98 let has_model_step = self.model_step.is_some();
99
100 if !(has_agent_step || has_model_step) {
101 trace!("spatial step skipped: no agent_step or model_step defined");
102 return Ok(());
103 }
104
105 if self.agents_first {
106 self.step_agents_spatial()?;
107 self.step_model();
108 } else {
109 self.step_model();
110 self.step_agents_spatial()?;
111 }
112
113 self.time = match self.time {
114 Time::Discrete(t) => Time::Discrete(t.saturating_add(1)),
115 Time::Continuous(t) => Time::Continuous(t + 1.0),
116 };
117
118 debug!(time = %self.time, agents = self.agents.len(), "spatial step completed");
119 Ok(())
120 }
121
122 pub fn run_spatial(&mut self, steps: usize) -> Result<(), InteractionError<S::Error>> {
124 for _ in 0..steps {
125 self.step_spatial()?;
126 }
127 Ok(())
128 }
129
130 fn apply_deferred_actions_spatial(
131 &mut self,
132 deferred: &mut Vec<crate::step_context::DeferredAction<A>>,
133 ) -> Result<(), InteractionError<S::Error>> {
134 use crate::step_context::DeferredAction;
135
136 if deferred.is_empty() {
137 return Ok(());
138 }
139
140 for action in deferred.drain(..) {
141 match action {
142 DeferredAction::RemoveAgent(id) => {
143 crate::interaction::remove_agent(self, id)?;
144 }
145 DeferredAction::InsertAgent(agent) => {
146 crate::interaction::add_agent(self, agent)?;
147 }
148 }
149 }
150 Ok(())
151 }
152
153 fn step_agents_spatial(&mut self) -> Result<(), InteractionError<S::Error>> {
154 let mut ids = std::mem::take(&mut self.schedule_buf);
155 ids.clear();
156 {
157 let mut sched = self.scheduler.borrow_mut();
158 sched.schedule_into(&*self, &mut ids);
159 }
160
161 if self.agent_step_ctx.is_none() {
162 self.schedule_buf = ids;
163 return Ok(());
164 }
165
166 let mut deferred = std::mem::take(&mut self.deferred_buf);
167 deferred.clear();
168
169 for &id in &ids {
170 let Some(mut agent_ref) = self.agents.get_mut(id) else {
171 continue;
172 };
173
174 {
175 let mut rng = self.rng.borrow_mut();
176 let mut sched = self.scheduler.borrow_mut();
177
178 let mut ctx = crate::step_context::StepContext {
179 space: &mut self.space,
180 properties: &mut self.properties,
181 rng: &mut *rng,
182 scheduler: &mut *sched,
183 deferred: &mut deferred,
184 _agent: PhantomData,
185 };
186
187 if let Some(step_fn) = self.agent_step_ctx.as_mut() {
188 step_fn(&mut *agent_ref, &mut ctx);
189 }
190 }
191
192 drop(agent_ref);
193 self.apply_deferred_actions_spatial(&mut deferred)?;
194 }
195
196 self.deferred_buf = deferred;
197 self.schedule_buf = ids;
198 Ok(())
199 }
200}
201
202pub type AgentStepFn<S, A, Props, R, Sch> =
209 Box<dyn for<'a> FnMut(&mut A, &mut crate::step_context::StepContext<'a, S, A, Props, R, Sch>)>;
210
211pub struct StandardModel<S, A, Store, Props, R, Sch>
240where
241 A: Agent,
242 S: Space,
243 Store: AgentStore<A>,
244 R: RngCore,
245{
246 pub(crate) agents: Store,
247 pub(crate) space: S,
248 pub(crate) scheduler: RefCell<Sch>,
249 pub(crate) properties: Props,
250 pub(crate) rng: RefCell<R>,
251 pub(crate) time: Time,
252 pub(crate) max_id: AgentId,
253 pub(crate) agents_first: bool,
254 pub(crate) agent_step_ctx: Option<AgentStepFn<S, A, Props, R, Sch>>,
255 pub(crate) model_step: Option<fn(&mut Self)>,
256 pub(crate) deferred_buf: Vec<crate::step_context::DeferredAction<A>>,
257 pub(crate) schedule_buf: Vec<AgentId>,
258 pub(crate) agent_marker: PhantomData<A>,
259}
260
261impl<S, A, Store, Props, R, Sch> StandardModel<S, A, Store, Props, R, Sch>
262where
263 A: Agent,
264 S: Space,
265 Store: AgentStore<A>,
266 R: RngCore,
267 Sch: Scheduler<Self>,
268{
269 #[allow(clippy::too_many_arguments)]
270 pub fn new(
283 agents: Store,
284 space: S,
285 scheduler: Sch,
286 properties: Props,
287 rng: R,
288 agent_step_ctx: Option<AgentStepFn<S, A, Props, R, Sch>>,
289 model_step: Option<fn(&mut Self)>,
290 agents_first: bool,
291 ) -> Self {
292 let max_id = agents.iter_ids().into_iter().max().unwrap_or(0);
293 Self {
294 agents,
295 space,
296 scheduler: RefCell::new(scheduler),
297 properties,
298 rng: RefCell::new(rng),
299 time: Time::Discrete(0),
300 max_id,
301 agents_first,
302 agent_step_ctx,
303 model_step,
304 deferred_buf: Vec::new(),
305 schedule_buf: Vec::new(),
306 agent_marker: PhantomData,
307 }
308 }
309
310 pub fn new_base(agents: Store, space: S, scheduler: Sch, properties: Props, rng: R) -> Self {
320 Self::new(agents, space, scheduler, properties, rng, None, None, true)
321 }
322
323 pub fn new_with_agent_step(
328 agents: Store,
329 space: S,
330 scheduler: Sch,
331 properties: Props,
332 rng: R,
333 agent_step_ctx: impl for<'a> FnMut(&mut A, &mut crate::step_context::StepContext<'a, S, A, Props, R, Sch>)
334 + 'static,
335 agents_first: bool,
336 ) -> Self {
337 Self::new(
338 agents,
339 space,
340 scheduler,
341 properties,
342 rng,
343 Some(Box::new(agent_step_ctx)),
344 None,
345 agents_first,
346 )
347 }
348
349 pub fn new_with_model_step(
351 agents: Store,
352 space: S,
353 scheduler: Sch,
354 properties: Props,
355 rng: R,
356 model_step: fn(&mut Self),
357 agents_first: bool,
358 ) -> Self {
359 Self::new(
360 agents,
361 space,
362 scheduler,
363 properties,
364 rng,
365 None,
366 Some(model_step),
367 agents_first,
368 )
369 }
370
371 pub fn with_agent_step_ctx(
373 mut self,
374 agent_step_ctx: impl for<'a> FnMut(&mut A, &mut crate::step_context::StepContext<'a, S, A, Props, R, Sch>)
375 + 'static,
376 ) -> Self {
377 self.agent_step_ctx = Some(Box::new(agent_step_ctx));
378 self
379 }
380
381 pub fn with_model_step(mut self, model_step: fn(&mut Self)) -> Self {
383 self.model_step = Some(model_step);
384 self
385 }
386
387 pub fn with_agents_first(mut self, agents_first: bool) -> Self {
389 self.agents_first = agents_first;
390 self
391 }
392
393 pub fn time(&self) -> Time {
395 self.time
396 }
397
398 pub fn rng_mut(&self) -> RefMut<'_, R> {
400 self.rng.borrow_mut()
401 }
402
403 pub fn space(&self) -> &S {
405 &self.space
406 }
407
408 pub fn space_mut(&mut self) -> &mut S {
410 &mut self.space
411 }
412
413 pub fn properties(&self) -> &Props {
415 &self.properties
416 }
417
418 pub fn properties_mut(&mut self) -> &mut Props {
420 &mut self.properties
421 }
422
423 pub fn agent(&self, id: AgentId) -> Option<Ref<'_, A>> {
425 self.agents.get(id)
426 }
427
428 pub fn agent_mut(&self, id: AgentId) -> Option<RefMut<'_, A>> {
430 self.agents.get_mut(id)
431 }
432
433 pub fn insert_agent(&mut self, agent: A) -> Result<(), A> {
438 let id = agent.id();
439 if self.agents.contains(id) {
440 return Err(agent);
441 }
442 self.agents.insert(agent);
443 if id > self.max_id {
444 self.max_id = id;
445 }
446 Ok(())
447 }
448
449 pub fn remove_agent(&mut self, id: AgentId) -> Option<A> {
451 self.agents.remove(id)
452 }
453
454 pub fn next_id(&mut self) -> AgentId {
456 self.max_id += 1;
457 self.max_id
458 }
459
460 pub fn step(&mut self) {
465 let has_agent_step = self.agent_step_ctx.is_some();
466 let has_model_step = self.model_step.is_some();
467
468 if !(has_agent_step || has_model_step) {
469 trace!("step skipped: no agent_step or model_step defined");
470 return;
471 }
472
473 if self.agents_first {
474 self.step_agents();
475 self.step_model();
476 } else {
477 self.step_model();
478 self.step_agents();
479 }
480
481 self.time = match self.time {
482 Time::Discrete(t) => Time::Discrete(t.saturating_add(1)),
483 Time::Continuous(t) => Time::Continuous(t + 1.0),
484 };
485
486 debug!(time = %self.time, agents = self.agents.len(), "step completed");
487 }
488
489 pub fn step_n(&mut self, n: usize) {
491 for _ in 0..n {
492 self.step();
493 }
494 }
495
496 pub fn run(&mut self, steps: usize) {
498 self.step_n(steps);
499 }
500
501 fn apply_deferred_actions(
502 &mut self,
503 deferred: &mut Vec<crate::step_context::DeferredAction<A>>,
504 ) {
505 use crate::step_context::DeferredAction;
506
507 if deferred.is_empty() {
508 return;
509 }
510
511 for action in deferred.drain(..) {
512 match action {
513 DeferredAction::RemoveAgent(id) => {
514 self.remove_agent(id);
515 }
516 DeferredAction::InsertAgent(agent) => {
517 let _ = self.insert_agent(agent);
518 }
519 }
520 }
521 }
522
523 fn step_agents(&mut self) {
524 let mut ids = std::mem::take(&mut self.schedule_buf);
525 ids.clear();
526 {
527 let mut sched = self.scheduler.borrow_mut();
528 sched.schedule_into(&*self, &mut ids);
529 }
530
531 if self.agent_step_ctx.is_none() {
532 self.schedule_buf = ids;
533 return;
534 }
535
536 let mut deferred = std::mem::take(&mut self.deferred_buf);
537 deferred.clear();
538
539 for &id in &ids {
540 let Some(mut agent_ref) = self.agents.get_mut(id) else {
541 continue;
542 };
543
544 {
545 let mut rng = self.rng.borrow_mut();
546 let mut sched = self.scheduler.borrow_mut();
547
548 let mut ctx = crate::step_context::StepContext {
549 space: &mut self.space,
550 properties: &mut self.properties,
551 rng: &mut *rng,
552 scheduler: &mut *sched,
553 deferred: &mut deferred,
554 _agent: PhantomData,
555 };
556
557 if let Some(step_fn) = self.agent_step_ctx.as_mut() {
558 step_fn(&mut *agent_ref, &mut ctx);
559 }
560 }
561
562 drop(agent_ref);
563
564 self.apply_deferred_actions(&mut deferred);
565 }
566
567 self.deferred_buf = deferred;
568 self.schedule_buf = ids;
569 }
570
571 fn step_model(&mut self) {
572 if let Some(step_fn) = self.model_step {
573 step_fn(self);
574 }
575 }
576
577 pub fn agents(&self) -> impl Iterator<Item = Ref<'_, A>> {
583 self.agents
584 .iter_ids()
585 .into_iter()
586 .filter_map(|id| self.agents.get(id))
587 }
588
589 pub fn agents_len(&self) -> usize {
591 self.agents.len()
592 }
593}
594
595impl<S, A, Store, Props, R, Sch> HasAgentIds for StandardModel<S, A, Store, Props, R, Sch>
596where
597 A: Agent,
598 S: Space,
599 Store: AgentStore<A>,
600 R: RngCore,
601{
602 fn agent_ids(&self) -> Vec<AgentId> {
603 self.agents.iter_ids()
604 }
605
606 fn agent_ids_into(&self, buf: &mut Vec<AgentId>) {
607 self.agents.iter_ids_into(buf);
608 }
609}
610
611impl<S, A, Store, Props, R, Sch> Model for StandardModel<S, A, Store, Props, R, Sch>
612where
613 A: Agent,
614 S: Space,
615 Store: AgentStore<A>,
616 R: rand::RngCore,
617{
618 type Agent = A;
619 type Space = S;
620 type Properties = Props;
621 type Rng = R;
622
623 type AgentRef<'a>
625 = Ref<'a, A>
626 where
627 Self: 'a;
628 type AgentRefMut<'a>
629 = RefMut<'a, A>
630 where
631 Self: 'a;
632
633 fn time(&self) -> Time {
634 self.time
635 }
636
637 fn rng_mut(&self) -> impl std::ops::DerefMut<Target = Self::Rng> + '_ {
638 self.rng.borrow_mut()
639 }
640
641 fn space(&self) -> &Self::Space {
642 &self.space
643 }
644
645 fn properties(&self) -> &Self::Properties {
646 &self.properties
647 }
648
649 fn properties_mut(&mut self) -> &mut Self::Properties {
650 &mut self.properties
651 }
652
653 fn agent(&self, id: AgentId) -> Option<Self::AgentRef<'_>> {
654 self.agents.get(id)
655 }
656
657 fn agent_mut(&self, id: AgentId) -> Option<Self::AgentRefMut<'_>> {
658 self.agents.get_mut(id)
659 }
660}