Skip to main content

phago_core/primitives/
sense.rs

1//! SENSE — Chemotaxis
2//!
3//! Cells navigate by sensing chemical gradients. A neutrophil detects
4//! increasing concentrations of inflammatory signals and moves toward
5//! the source. The cell doesn't know where the problem is — it follows
6//! the gradient.
7//!
8//! Agents also emit signals (autoinducers) for quorum sensing. When
9//! enough agents emit presence signals, the collective detects its own
10//! density and can trigger phase transitions.
11
12use crate::substrate::Substrate;
13use crate::types::*;
14
15/// Detect environmental signals, compute gradients, and emit signals.
16///
17/// Sensing is local, not global. An agent only perceives signals within
18/// its sensing radius — it has no access to the full substrate state.
19/// Navigation emerges from following local gradients, not from knowing
20/// the global map.
21pub trait Sense {
22    /// The radius within which this agent can sense signals.
23    fn sense_radius(&self) -> f64;
24
25    /// Read signals from the local environment.
26    ///
27    /// Returns only signals within `sense_radius` of the agent's position.
28    fn sense(&self, substrate: &dyn Substrate) -> Vec<Signal> {
29        let position = self.sense_position();
30        let radius = self.sense_radius();
31        substrate
32            .signals_near(&position, radius)
33            .into_iter()
34            .cloned()
35            .collect()
36    }
37
38    /// The position from which this agent senses.
39    fn sense_position(&self) -> Position;
40
41    /// Compute the gradient — direction of increasing signal strength.
42    ///
43    /// Like a cell comparing receptor binding rates across its surface.
44    fn gradient(&self, substrate: &dyn Substrate) -> Vec<Gradient>;
45
46    /// Emit a signal into the substrate.
47    ///
48    /// Used for quorum sensing (presence signals), alerting
49    /// (anomaly signals), and coordination (capability signals).
50    fn emit(&self, signal: Signal, substrate: &mut dyn Substrate) {
51        substrate.emit_signal(signal);
52    }
53
54    /// Determine next orientation based on sensed gradients.
55    ///
56    /// Returns where the agent should move or what it should prioritize.
57    fn orient(&self, gradients: &[Gradient]) -> Orientation;
58}