Agents
Agent Base Class
- class econsimulacra.agents.base.Agent(agent_id, agent_name, env_service_dic, prng=None, config=None)[source]
-
Agent class.
Once you define the agent class inheriting this agent ABC class, environment automatically generate agents using the class you define. act(self, obs: ObsT) method is the only method that must be implemented in the agent class you define, and it will be called by environment at each step to get the action of the agent.
- Parameters:
- self_assign_name(config)[source]
Assign a name to the agent based on the configuration.
If “name” is not provided in the config, the agent name will be the default name assigned by environment.
- abstractmethod async act(obs)[source]
Perform an action based on the observation (abstract method).
- exchange_goods(get_item_name=None, get_item_amount=None, give_item_name=None, give_item_amount=None)[source]
Exchange goods in the agent’s inventory.
- Parameters:
get_item_name (Optional[str]) – the name of the item to get (optional).
get_item_amount (Optional[float | int]) – the amount of the item to get (optional, must be provided if get_item_name is provided).
give_item_name (Optional[str]) – the name of the item to give (optional).
give_item_amount (Optional[float | int]) – the amount of the item to give (optional, must be provided if give_item_name is provided).
- Return type:
None
- provide_info4all_agents()[source]
provide information for all agents.
- Returns:
a list of information keys that the agent can provide for all agents.
- Return type:
Note
Usually called by observation providers registered in econsimulacra.environment.base._build_observation_registry. Currently, the following built-in observation provider is supported: econsimulacra.environment.base._obs_others_pos If another agent is requesting “others_pos” information (i.e., “others_pos” is in the self.request_obses of the another agent), the agent can provide its position information to them by adding “self_pos” in self.info4all_agents.
- provide_info4co_located_agents()[source]
provide information for those agents who are co-located.
- Returns:
a list of information keys that the agent can provide for those agents who are co-located.
- Return type:
Note
Usually called by observation providers registered in econsimulacra.environment.base._build_observation4co_located_agents_registry. Currently, the following built-in observation provider is supported: econsimulacra.environment.base._obs_others_inventory If another agent who is co-located with the agent is requesting “others_inventory” informaation (i.e., “others_inventory” is in the self.request_obses of the another agent), the agent can provide its inventory information to them by adding “inventory” in self.info4co_located_agents.
- provide_info4allowed_agents()[source]
provide information for those agents who are allowed.
- Returns:
a list of information keys that the agent can provide for those agents who are is_rich_info_allowed.
- Return type:
Note
Usually called by observation providers registered in econsimulacra.environment.base._build_observation4allowed_agents_registry. Currently, built-in observation provider is not supported, but users can implement their own observation provider and register it in econsimulacra.environment.base._build_observation4allowed_agents_registry to provide rich information for those agents who are is_rich_info_allowed.
LLM Agent
- class econsimulacra.agents.llm_agent.LLMAgent(agent_id, agent_name, env_service_dic, prng=None, config=None)[source]
-
LLM agent that uses a language model to generate actions based on observations.
The LLMAgent relies on the environment services to provide an LLM client, a prompt builder, and optionally a persona builder. The agent constructs prompts based on the current observation and persona (if applicable), sends the prompt to the LLM client, and returns the generated response as its action.
- Parameters:
- self_assign_name(config)[source]
Assign name to the agent, potentially using the persona builder if available.
- Parameters:
config (dict) – Configuration dictionary for the agent. This may include a “personaConfig” key with configuration for the persona builder.
See also
econsimulacra.llm_services.personas.base.PersonaBuilder
- async act(obs)[source]
Generate an action based on the current observation.
- Parameters:
obs (dict) – The current observation for the agent. The structure of this dictionary depends on the environment.
- Returns:
- The action generated by the agent based on the current observation.
The generated action is applied in the environment.
- Return type:
Note
This method constructs a prompt by combining the persona prompt (if a persona builder is available) and the observation prompt (constructed by the prompt builder). It then sends the prompt to the LLM client to generate a response.
Government Agent
- class econsimulacra.agents.government.Government(agent_id, agent_name, env_service_dic, prng=None, config=None)[source]
-
Rule-based government agent.
This class only posts tweets based on a predefined schedule and does not interact with other agents or the environment in any other way. The policy must be defined separately by the user as “events”.
- Parameters:
- self_assign_name(config)[source]
Assign the agent’s name from the config.
To easily determine the name of the government agent, we require that the config contains a “name” field without adding agent_id.
Auto-Reactor Agent
- class econsimulacra.agents.auto_reacter.AutoReactLLMAgent(agent_id, agent_name, env_service_dic, prng=None, config=None)[source]
Bases:
LLMAgentAn LLMAgent that automatically reacts to all incoming orders and proposals.
This wrapper enforces deterministic acceptance of transactional intents (i.e., incoming_orders and incoming_proposals) posterior to, or independently of, the LLM-generated decision. The primary objective is to eliminate non-responsive or economically irrational behaviors (e.g., ignoring valid orders) that often arise from stochastic LLM outputs in supply-side agents such as retailers and restaurants.
In socio-economic EconSimulacra, supply-side agents are expected to process transactions reliably. However, vanilla LLMAgents may omit reactions due to prompt misalignment or token truncation. This wrapper guarantees that all valid incoming transactional requests are accepted, thereby preserving simulation consistency and preventing deadlocks in the market mechanism.
- Parameters:
- async act(obs)[source]
Automatically react to all incoming orders and proposals.
Get the LLM-generated response and then overwrite the reactions field to ensure that all incoming transactional intents are accepted.
- judge_reaction(incoming_transactional_intent, current_inventory, is_order)[source]
Judge whether to react to an incoming transactional intent based on the current inventory.
- Parameters:
incoming_transactional_intent (dict[str, Any]) – A dictionary representing the incoming order or proposal that the agent is evaluating.
current_inventory (dict[str, float | int]) – A dictionary representing the agent’s current inventory before reacting to the intent.
is_order (bool) – A boolean indicating whether the incoming transactional intent is an order (True) or a proposal (False).
- Returns:
- True if the agent should react to the incoming transactional intent,
False otherwise.
- Return type:
Note
Always True as long as the agent has sufficient inventory to fulfill the intent.
Rule-Based Household
- class econsimulacra.agents.households.household.RuleBasedHousehold(agent_id, agent_name, env_service_dic, prng=None, config=None, decision_policy=None, supplemental_policies=[])[source]
-
EconSimulacra adapter for the complete rule-based household.
The final action combines the core fragment and every supplemental fragment:
\[A_t=\Pi_E(a_t^{\rm core}) \oplus\bigoplus_{j=1}^{m}\Pi_E(a_{t,j}^{\rm supplemental}),\]where \(\Pi_E\) removes disabled keys and \(\oplus\) is implemented by
_compose_fragments().Usage: add a custom action
class WeatherTweetPolicy: def decide(self, context, state): if context.hour == 8: return {"tweet": "Good morning."} return {} class SocialHousehold(RuleBasedHousehold): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.add_supplemental_policy(WeatherTweetPolicy()) simulator.register_classes([SocialHousehold])
Set the agent config
typetoSocialHousehold. A custom scalar key must not conflict with another fragment, and any key listed indisabledActionsis removed before composition.- Parameters:
agent_id (int)
agent_name (str)
prng (Optional[Random])
decision_policy (Optional[HouseholdDecisionPolicy])
supplemental_policies (list[SupplementalPolicy])
- build_decision_policy()[source]
Build the default core decision policy.
- Returns:
Policy wired with default physiology, mobility, shopping, and action capabilities.
- Return type:
- add_supplemental_policy(policy)[source]
Register one custom policy after existing supplemental policies.
- Parameters:
policy (SupplementalPolicy) – Object implementing synchronous or asynchronous
decide(context, state).- Return type:
None
- async act(obs)[source]
Orchestrate one household decision.
- Parameters:
obs (dict[str, Any]) – EconSimulacra observation mapping for the current step.
- Returns:
Composed, capability-filtered EconSimulacra action mapping.
- Return type:
\[O_t\to o_t\to x_t\to (a_t^{\rm core},a_t^{\rm supplemental,*}) \to A_t.\]
- get_time_step(obs)[source]
Extract the canonical environment step with legacy fallbacks.
- Parameters:
obs (dict[str, Any]) – Raw observation that may contain
time_stepor numerictime.- Returns:
Integer simulation step.
- Return type:
Note
Counting calls is the last resort because sleeping and non-walking agents can legitimately skip calls to
act().
- get_current_hour(obs, time_step)[source]
Extract wall-clock hour with a step-derived compatibility fallback.
- Parameters:
- Returns:
Local hour in the interval
[0, 24).- Return type:
Note
Display time is authoritative when it is a valid ISO string. This keeps circadian decisions aligned after sleep or automatic travel skips calls to
act().
Household Decision Policy
- class econsimulacra.agents.households.policy.ActionCapabilities(disabled=frozenset({}))[source]
Bases:
objectRepresent the action keys enabled for an agent.
EconSimulacra configurations name unavailable actions in
disabledActions. Let \(\mathcal{A}\) be the universe of action keys and \(\mathcal{D}\) the configured disabled set. The feasible set is\[\mathcal{A}^{\mathrm{enabled}}=\mathcal{A}\setminus\mathcal{D}.\]Core policies query this object before mutating state.
filter()is a second boundary check for reactions and third-party supplemental policies. Unknown names are retained in \(\mathcal{D}\) and filtered literally, which permits future EconSimulacra action types without changing this class.- classmethod from_config(config)[source]
Construct capabilities from an agent configuration.
- filter(action_fragment)[source]
Remove disabled keys from an action fragment.
- Parameters:
action_fragment (dict[str, Any]) – Partial action mapping to restrict.
- Returns:
New mapping containing only enabled keys.
- Return type:
For fragment \(a\), the returned mapping is the restriction \(a|_{\mathcal{A}^{\mathrm{enabled}}}\). The input is not mutated.
- class econsimulacra.agents.households.policy.DecisionSignals(can_move, can_sleep, can_consume, can_order, should_sleep, can_eat, should_eat)[source]
Bases:
objectPrecomputed feasibility and demand signals for one decision.
- Parameters:
can_move (bool) – Whether
moveis enabled.can_sleep (bool) – Whether
sleep_durationis enabled.can_consume (bool) – Whether
consumptionsis enabled.can_order (bool) – Whether
ordersis enabled.should_sleep (bool) – Whether enabled sleep demand has reached onset.
can_eat (bool) – Whether consumption is enabled and food is available.
should_eat (bool) – Whether enabled scheduled-meal demand is active.
- class econsimulacra.agents.households.policy.HouseholdDecisionPolicy(physiology, mobility, shopping, capabilities=None)[source]
Bases:
objectApply physiological and activity priorities to produce one core action.
This class is the sole arbiter among sleep, food, shopping, and mobility demands. The priority ordering is an explicit design assumption; it is not claimed as an empirical utility maximization result.
- Parameters:
physiology (PhysiologyModel) – Sleep, hunger, and meal policy.
mobility (MobilityModel) – Movement action adapter.
shopping (ShoppingModel) – Replenishment, store-choice, and order policy.
capabilities (Optional[ActionCapabilities]) – Enabled-action policy. All actions are enabled by default.
- decide(context, state)[source]
Return the highest-priority feasible household action.
The policy evaluates guards in the following strict lexicographic order and executes only the first applicable core branch:
Environment reports that the household is already sleeping: emit no core action.
Sleep and movement are enabled and sleep is due away from home: move home.
Consumption is enabled, hunger is critical, and food exists: eat at the current position.
Sleep is enabled and due at home: sleep.
Movement is enabled and a return-home trip is active and incomplete: continue it.
Consumption is enabled, a meal is due, and food exists: eat at the current position.
Orders are enabled, shopping is due, budget is positive, and no destination is active: choose a store. If movement is disabled, only co-located stores belong to the choice set.
A store trip is active: order on arrival and depart for home in the same action when movement is enabled, move toward the store when necessary, or cancel an infeasible trip.
- Movement is enabled and the household remains away from home: move
home.
Otherwise: normalize the current home/away mode and emit no core action.
Formally, let \(g_k(o_t,x_t)\in\{0,1\}\) denote applicability of branch \(k\) in that list and let \(a_k(o_t,x_t)\) be its state transition and action fragment. The selected branch is
\[k_t^*=\min\{k\in\{1,\ldots,10\}:g_k(o_t,x_t)=1\},\qquad a_t^{\mathrm{core}}=a_{k_t^*}(o_t,x_t).\]Branch 10 is unconditional, so the set is nonempty. Sleep demand, meal demand, food feasibility, shopping demand, and budget are defined by
PhysiologyModel.sleep_due(),PhysiologyModel.meal_due(),PhysiologyModel.can_eat(),ShoppingPolicy.shopping_due(), andShoppingPolicy.budget(). Critical hunger means \(G_t\geq G_{\mathrm{critical}}\). Home equality is exact tuple equality \(p_t=h\). If \(e_a=\mathbf{1}\{a\notin\mathcal{D}\}\) is the capability indicator for action key \(a\), every branch that emits \(a\) also includes \(e_a=1\) in its guard. Thus a disabled high-priority demand cannot block a lower-priority feasible branch.- Parameters:
context (DecisionContext) – Normalized current observation.
state (HouseholdState) – Mutable household state.
- Returns:
Exactly one core action fragment, possibly empty.
- Return type:
Before evaluating the priority branches, any co-located seller offers update this household’s store-specific price and availability beliefs.
- get_signals(context, state)[source]
Calculate action feasibility and physiological demand once.
- Parameters:
context (DecisionContext) – Normalized current observation.
state (HouseholdState) – Current household state.
- Returns:
Immutable signals shared by all priority rules this step.
- Return type:
- class econsimulacra.agents.households.policy.SupplementalPolicy(*args, **kwargs)[source]
Bases:
ProtocolProtocol for optional actions such as social-network behavior.
A supplemental policy observes the same context and mutable state as the core policy and returns an action fragment. It is evaluated after the core household decision, then combined by :class:RuleBasedHousehold._compose_fragments. The default list contains
ProposalReactionPolicy; additional policies can add independent behavior such as SNS actions.Implementations do not need to inherit this Protocol; providing a compatible synchronous or asynchronous
decide()method is sufficient.Usage
class HungerTweetPolicy: def decide(self, context, state): if state.hunger >= 0.8: return {"tweet": "I am getting hungry."} return {} class SocialHousehold(RuleBasedHousehold): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.add_supplemental_policy(HungerTweetPolicy()) simulator.register_classes([SocialHousehold])
The corresponding agent configuration uses
"type": "SocialHousehold". Disabled action keys returned by a custom policy are removed before composition. Custom policies should normally read rather than mutatestateso that core behavior remains independent.- decide(context, state)[source]
Return an action fragment to merge with the core decision.
- Parameters:
context (DecisionContext) – Normalized current observation and time.
state (HouseholdState) – Mutable household state after the core policy has run.
- Returns:
Partial EconSimulacra action mapping. Return an empty mapping when the supplemental policy has no action for this step.
- Return type:
- class econsimulacra.agents.households.policy.SocialMediaPolicy(config, prng, capabilities=None, tweet_renderer=None)[source]
Bases:
_SocialMediaPolicyRules,SupplementalPolicyGenerate a complete supplemental SNS action fragment.
- Parameters:
config (dict[str, Any]) –
socialRulehousehold configuration.prng (Random) – Shared seeded pseudo-random generator.
capabilities (Optional[ActionCapabilities]) – Household action capabilities used to avoid infeasible decisions and unnecessary Tiny LM calls.
tweet_renderer (Optional[TweetRenderer]) – Optional asynchronous renderer. It is required only when tweet actions are enabled.
Follow, unfollow, tweet-event occurrence, topic, sentiment, and style are selected by rules. The renderer controls wording only. This policy is asynchronous solely because text generation may take time; existing synchronous supplemental policies remain valid.
- async decide(context, state)[source]
Generate one supplemental social-network action fragment.
- Parameters:
context (DecisionContext) – Normalized current observation.
state (HouseholdState) – Household state after the core policy decision.
- Returns:
Mapping containing zero or more of
follow,unfollow, andtweet.- Return type:
- class econsimulacra.agents.households.policy.ProposalReactionPolicy[source]
Bases:
SupplementalPolicyReact to proposals from other agents.
This policy is the default supplemental policy for all households. It observes the same context and mutable state as the core policy and returns an action fragment. It is evaluated after the core household decision, then combined by :class:RuleBasedHousehold._compose_fragments.
- decide(context, state)[source]
Return a proposal-reaction action fragment.
- Parameters:
context (DecisionContext) – Normalized current observation and time.
state (HouseholdState) – Mutable household state after the core policy has run.
- Returns:
Partial EconSimulacra action mapping. Return an empty mapping when no proposal reactions are applicable.
- Return type:
Household Tweet Renderer
- class econsimulacra.agents.households.tweet_renderer.TweetTextGenerator(*args, **kwargs)[source]
Bases:
ProtocolProtocol implemented by an asynchronous tweet text generator.
- class econsimulacra.agents.households.tweet_renderer.TweetRenderer(text_generator, language='English', max_characters=140)[source]
Bases:
objectRender a rule-selected tweet intent with a small language model.
- Parameters:
text_generator (TweetTextGenerator) – Service that generates plain text asynchronously.
language (str) – Output language named in the prompt.
max_characters (int) – Maximum emitted tweet length.
The renderer controls wording only. Follow decisions, tweet timing, topic, sentiment, and style have already been fixed by rules before this class is called.
- async generate_tweet(intent, previous_tweet=None)[source]
Generate and sanitize one tweet from a structured intent.
- Parameters:
intent (TweetIntent) – Rule-selected tweet specification.
previous_tweet (str | None) – Most recent tweet used for exact duplicate removal.
- Returns:
Sanitized tweet, or
Noneafter empty or duplicate generation.- Return type:
str | None
- generate_prompt(intent)[source]
Generate a compact grounding prompt for a Tiny LM.
- Parameters:
intent (TweetIntent) – Rule-selected content specification.
- Returns:
Prompt that asks only for surface realization of the intent.
- Return type:
Household State and Context
- class econsimulacra.agents.households.states.HouseholdState(sleep_pressure, hunger, last_meal_elapsed, home=None, destination=None, mode='HOME', last_step=None, has_been_sleeping=False)[source]
Bases:
objectMutable state shared by the household’s policy components.
- Parameters:
sleep_pressure (float) – Homeostatic sleep stock \(H_t\).
hunger (float) – Bounded hunger stock \(G_t\).
last_meal_elapsed (float) – Hours since the last meal \(M_t\).
home (tuple[int, ...] | None) – Fixed initial position \(h\), or
Nonebefore first act.destination (tuple[int, ...] | None) – Active movement destination \(d_t\), if any.
mode (Literal['HOME', 'AWAY', 'SLEEPING', 'TRAVEL_STORE', 'WAITING_ORDER', 'RETURN_HOME', 'RETURN_HOME_SLEEP', 'RETURN_HOME_MEAL']) – Finite-state activity label \(z_t\).
last_step (int | None) – Last processed simulation step \(\ell_t\), if any.
sleeping_last_interval – Whether the preceding interval was asleep.
has_been_sleeping (bool)
The private state at decision step \(t\) is
\[x_t=(H_t,G_t,M_t,h,d_t,z_t,\ell_t,\sigma_t).\]
- class econsimulacra.agents.households.states.SocialState(hawkes_excitation=0.0, last_hawkes_step=None, last_memory_snapshot=<factory>, changed_memory_keys=(), empty_timeline_steps=<factory>, last_follow_step=None, last_unfollow_step=None, last_tweet_intent=None)[source]
Bases:
objectStore private state used by the household social-media policy.
- Parameters:
hawkes_excitation (float) – Current excitation above the baseline intensity.
last_hawkes_step (Optional[int]) – Last step at which excitation was decayed.
last_memory_snapshot (dict[str, Any]) – Previous relevant summarized-memory values.
changed_memory_keys (tuple[str, ...]) – Memory categories changed at the current step.
empty_timeline_steps (dict[int, int]) – Consecutive empty-tweet observations by followee.
last_follow_step (Optional[int]) – Most recent step at which follow was selected.
last_unfollow_step (Optional[int]) – Most recent step at which unfollow was selected.
last_tweet_intent (Optional[TweetIntent]) – Most recently realized tweet intent.
Tweet occurrence state is separate from
HouseholdStatebecause the Hawkes process and graph-management rules are supplemental behavior and do not alter sleep, hunger, mobility, or shopping state.- last_tweet_intent: TweetIntent | None = None
- class econsimulacra.agents.households.states.DecisionContext(obs, time_step, hour, current_pos, inventory)[source]
Bases:
objectNormalized observation supplied to every household policy.
- Parameters:
The adapter computes
\[\tau_t=(\tau_0+t\Delta)\bmod 24,\]where \(\tau_0\) is
startHourand \(\Delta\) isstepHours.
Household Stylized Models
- class econsimulacra.agents.households.stylized_models.PhysiologyModel(config, food_items, step_hours)[source]
Bases:
objectUpdate sleep pressure and hunger and create physiological actions.
This is a stylized discrete-time model inspired by the exponential sleep Process S and sinusoidal Process C (Borbély, 1982), plus empirical circadian meal timing (de Castro, 1987). It is not a calibrated reproduction.
References
Borbély, A. A. (1982). A two process model of sleep regulation. Human Neurobiology, 1(3), 195-204. https://pubmed.ncbi.nlm.nih.gov/7185792/
de Castro, J. M. (1987). Circadian rhythms of the spontaneous meal pattern, macronutrient intake, and mood of humans. Physiology & Behavior, 40(4), 437-446. https://doi.org/10.1016/0031-9384(87)90028-X
- initialize_state()[source]
Create the initial household state.
- Returns:
State with configured initial sleep pressure and hunger, and an infinite elapsed meal interval.
- Return type:
\[H_0=H_{\mathrm{init}},\quad G_0=G_{\mathrm{init}},\quad M_0=\infty.\]
- update_state(state, step)[source]
Advance physiological stocks to
step.- Parameters:
state (HouseholdState) – Mutable household state to update in place.
step (int) – Current nonnegative simulation step.
- Return type:
None
For elapsed hours \(\delta_t\), lower and upper asymptotes \(L<U\), and time constants \(\theta_s,\theta_w>0\),
\[\begin{split}H_t=\begin{cases} L+(H_{t-1}-L)e^{-\delta_t/\theta_s},&\sigma_{t-1}=1,\\ U-(U-H_{t-1})e^{-\delta_t/\theta_w},&\sigma_{t-1}=0. \end{cases}\end{split}\]Hunger evolves as
\[G_t=\min\{1,G_{t-1}+\rho_t\delta_t\},\qquad M_t=M_{t-1}+\delta_t,\]using the configured awake or asleep rate \(\rho_t\).
- should_sleep(state, current_hour)[source]
Test the sleep-onset condition.
- Parameters:
state (HouseholdState) – Household state containing current sleep pressure.
current_hour (float) – Current local clock hour in
[0, 24).
- Returns:
Truewhen homeostatic plus circadian pressure reaches onset.- Return type:
\[C(\tau)=A\cos\left(\frac{2\pi(\tau-\phi)}{24}\right),\qquad D_t^{\mathrm{sleep}}=\mathbf{1}\{H_t+C(\tau_t)\geq\eta_{\rm on}\}.\]
- generate_sleep_action(state, current_hour)[source]
Enter sleep mode and construct a sleep action.
- Parameters:
state (HouseholdState) – Mutable household state to mark as sleeping.
current_hour (float) – Current local clock hour used to predict wake time.
- Returns:
Action containing the predicted integer
sleep_duration.- Return type:
For maximum duration \(N\), the chosen duration is the first \(n\in\{1,\ldots,N\}\) at which projected pressure reaches the wake threshold, or \(N\) if no such step exists.
- should_eat(state, current_hour)[source]
Test the scheduled-meal condition.
- Parameters:
state (HouseholdState) – Household state containing hunger and elapsed meal time.
current_hour (float) – Current local clock hour in
[0, 24).
- Returns:
Truewhen minimum spacing and weighted meal demand both hold.- Return type:
\[S(\tau)=\max_{\mu\in\mathcal K} \exp\left[-\frac{d_{24}(\tau,\mu)^2}{2w^2}\right],\]\[D_t^{\mathrm{meal}}=\mathbf{1}\{M_t\geq m_{\min}\ \land\ G_t+\omega S(\tau_t)\geq\eta_m\}.\]
- generate_eat_action(state, inventory)[source]
Allocate one meal and update hunger.
- Parameters:
state (HouseholdState) – Mutable household state to update after consumption.
inventory (dict[str, float]) – Current self-inventory keyed by item name.
- Returns:
consumptionsrecords for positive food quantities, or an empty mapping when no positive quantity can be consumed.- Return type:
For food share \(s_i\) and energy per unit \(e_i\),
\[c_{i,t}=\min\left\{I_t(i), \frac{\max(0,G_t)s_i}{\max(e_i,10^{-12})}\right\}.\]
- class econsimulacra.agents.households.stylized_models.ShoppingModel(config, food_items, cash_name, prng, shopping_items=None)[source]
Bases:
objectManage replenishment, store choice, budgeting, and order settlement.
The replenishment trigger is an \((s,S)\)-style rule inspired by the classical inventory policy (Scarf, 1960). Here it is a household heuristic, not the solution of Scarf’s dynamic program: reorder points and target stocks are fixed configuration values and the basket is cash constrained.
Store choice uses a multinomial logit over observed stores, following the random-utility form associated with conditional logit (McFadden, 1974). Every household maintains seller-specific expected prices and availability probabilities, updates them after co-located observations, and values coverage according to item-specific replenishment importance. Travel is embedded in an activity sequence (home, shopping, home), a minimal stylization of activity-schedule demand models (Bowman & Ben-Akiva, 2001).
All stochastic choice uses the injected
random.Randominstance. A fixed seed, observation order, configuration, and initial state therefore reproduce the same choice sequence.References
Bowman, J. L., & Ben-Akiva, M. E. (2001). Activity-based disaggregate travel demand model system with activity schedules. Transportation Research Part A: Policy and Practice, 35(1), 1-28. https://doi.org/10.1016/S0965-8564(99)00043-9
McFadden, D. (1974). Conditional logit analysis of qualitative choice behavior. In P. Zarembka (Ed.), Frontiers in econometrics (pp. 105-142). Academic Press. https://eml.berkeley.edu/reprints/mcfadden/zarembka.pdf
Scarf, H. E. (1960). The optimality of (S, s) policies in the dynamic inventory problem. In K. J. Arrow, S. Karlin, & P. Suppes (Eds.), Mathematical methods in the social sciences, 1959 (pp. 196-202). Stanford University Press. https://cir.nii.ac.jp/crid/1572824499232680448
- Parameters:
- should_shop(inventory)[source]
Return whether any stock is at or below its reorder point.
- Parameters:
inventory (dict[str, float]) – Current self-inventory keyed by item name.
- Returns:
Whether at least one purchase target has reached its reorder point.
- Return type:
For purchase targets \(\mathcal{I}\) and configured reorder point \(s_i\),
\[D_t^{\mathrm{shop}}= \mathbf{1}\{\exists i\in\mathcal{I}:I_t(i)\leq s_i\}.\]
- get_budget(inventory)[source]
Return cash available after reserve and basket-share constraints.
- Parameters:
inventory (dict[str, float]) – Current self-inventory containing the configured cash.
- Returns:
Nonnegative maximum basket expenditure.
- Return type:
Let \(Y_t=I_t(c)\) be holdings of configured cash item \(c\), \(R\geq0\) the cash reserve, and \(\alpha\geq0\) the maximum basket share. The shopping budget is
\[B_t=\max\{0,\min(Y_t-R,\alpha Y_t)\}.\]
- get_stores(context)[source]
Return every visible non-household agent as a store candidate.
- Parameters:
context (DecisionContext) – Observation context containing optional
others_pos.- Returns:
Visible sellers in observation order. Example:
[ { "agent_id": 10, "agent_name": "MarketEast", "is_household": False, "pos": (2, 3), }, { "agent_id": 12, "agent_name": "MarketWest", "is_household": False, "pos": (8, 4), }, ]
- Return type:
Seller order is preserved from
others_posbecause it is also the deterministic tie order used by store choice.
- update_beliefs(context)[source]
Update store-specific beliefs from co-located seller observations.
- Parameters:
context (DecisionContext) – Observation containing optional
others_inventory.- Return type:
None
For seller \(j\), item \(i\), learning rate \(\rho\in[0,1]\), observed posted price \(p_{ij}\) and availability indicator \(a_{ij}\in\{0,1\}\), beliefs follow
\[\hat p_{ij}\leftarrow(1-\rho_p)\hat p_{ij}+\rho_p p_{ij}, \qquad \hat a_{ij}\leftarrow(1-\rho_a)\hat a_{ij}+\rho_a a_{ij}.\]An item is observed available when the seller reports a positive or masked amount. A missing item is observed unavailable. Price is updated only when the item is offered. Beliefs are held by this model instance and therefore are not shared across households.
- choose_store(current_pos, stores, inventory)[source]
Choose a store with an importance-weighted belief logit.
- Parameters:
- Returns:
Sampled store record, or
Nonefor an empty choice set.- Return type:
Let \(q_i=\max(0,T_i-I_t(i))\) be desired replenishment, \(w_i\geq0\) item importance, \(\bar p_i\) the household price prior, \(\hat a_{ij}\in[0,1]\), \(\hat p_{ij}\) the household’s availability and price beliefs for store \(j\), and \(B_t>0\) the household’s shopping budget. The importance-weighted desired quantity is
\[W_t=\sum_i w_iq_i.\]For \(W_t>0\), expected coverage and price savings relative to the household prior are
\[C_{tj}=\frac{\sum_iw_iq_i\hat a_{ij}}{W_t},\qquad R_{tj}=\frac{\sum_iw_iq_i\hat a_{ij} (\bar p_i-\hat p_{ij})/\bar p_i}{W_t}.\]Expected basket expenditure and budget pressure are
\[E_{tj}=\sum_iq_i\hat a_{ij}\max(0,\hat p_{ij}),\qquad L_{tj}=E_{tj}/B_t.\]\[D_{tj}=\max_k|p_{t,k}-d_{j,k}|,\qquad V_{tj}=\beta_P R_{tj}+\beta_A C_{tj} -\beta_B L_{tj}-\beta_D D_{tj}.\]A store is sampled with
\[P(J_t=j\mid o_t,x_t)= \frac{\exp(V_{tj})}{\sum_{r\in\mathcal{J}_t}\exp(V_{tr})}.\]Because \(L_{tj}\) divides by the household-specific budget, the same expensive basket deters a budget-constrained household more than a wealthy one. Unavailable goods contribute no artificial price saving and reduce coverage, so a store cannot look cheap merely because it is expected to carry few needed goods. Larger
itemImportancemakes shortages of necessities contribute more strongly than shortages of preference goods. Numerically,max(V)is subtracted before exponentiation. An empty choice set, nonpositive budget, or basket with zero weighted need returnsNone.
- generate_order_action(context)[source]
Build a budget-feasible basket from a co-located seller.
- Parameters:
context (DecisionContext) – Observation containing current inventory and co-located seller inventories.
- Returns:
Order records, or an empty mapping when no order is feasible.
- Return type:
The first matching seller in
others_inventoryis used. Items are processed by descendingitemImportancewith configured order as the stable tie break, so a tight budget fills necessities first. Let \(p_i>0\) be observed price (zero or negative price removes the affordability bound), \(A_i\) observed seller stock when numeric and \(+\infty\) otherwise, and \(B_1=B_t\). Then\[q_i^*=\min\{\max(0,T_i-I_t(i)),A_i\},\]\[\begin{split}q_i=\begin{cases} \min\{q_i^*,B_i/p_i\},&p_i>0,\\ q_i^*,&p_i\leq0, \end{cases} \qquad B_{i+1}=B_i-p_iq_i.\end{split}\]Positive \(q_i\) values become EconSimulacra orders with TTL 2. EconSimulacra processes
ordersbeforemovein the same action dictionary and exposes resulting inventory in the next observation; therefore no settlement-wait state is retained. An empty seller set or basket produces no action.
- class econsimulacra.agents.households.stylized_models.MobilityModel[source]
Bases:
objectTranslate an activity destination into EconSimulacra movement.
Destination choice belongs to the activity policy; this component only adapts a chosen position to the environment action schema. Reissuing the destination also makes movement intent explicit if environment-side motion persistence changes.
- select_mobility(context)[source]
Select a mobility mode from the current observation.
- Parameters:
context (DecisionContext) – Normalized current observation.
- Returns:
Name of the mobility mode to use.
- Return type:
Note
An active journey retains its current mode when that mode remains available. A new journey uses the mode with the highest effective velocity. Walking preserves compatibility when mobility observations are absent.
- generate_move_action(context, state, destination, mode)[source]
Persist intent and reissue the destination for this step.
- Parameters:
context (DecisionContext) – Normalized current observation used to select mobility.
state (HouseholdState) – Mutable household state in which to persist movement intent.
mode (Literal['HOME', 'AWAY', 'SLEEPING', 'TRAVEL_STORE', 'WAITING_ORDER', 'RETURN_HOME', 'RETURN_HOME_SLEEP', 'RETURN_HOME_MEAL']) – Activity-mode label associated with the trip.
- Returns:
moveaction targetingdestinationwith its mobility mode.- Return type:
Note
Availability and effective velocity are supplied by the environment; ownership and fuel requirements are not recalculated here.
For selected destination \(d\) and activity label \(z\), the state transition and action are
\[(d_t,z_t,\sigma_t)\leftarrow(d,z,0),\qquad a_t=\{\mathtt{move}:d,\mathtt{mobility}:m\}.\]
- class econsimulacra.agents.households.stylized_models.ProposalReactionModel[source]
Bases:
objectDefault model for unsolicited proposals.
This is a boundary policy rather than a behavioral model: households do not initiate swaps and deterministically reject every observed proposal.
- generate_reactions(context, state)[source]
Reject every incoming swap proposal.
- Parameters:
context (DecisionContext) – Observation containing optional
incoming_proposals.state (HouseholdState) – Household state; unused because rejection is stateless.
- Returns:
Proposal-rejection reactions, or an empty mapping.
- Return type: