mirror of
https://github.com/velocitatem/PHANTOM.git
synced 2026-05-31 16:43:36 +00:00
chore: properly developing
This commit is contained in:
48
engine/lib/behavior.py
Normal file
48
engine/lib/behavior.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
from sim.rl.behavior_loader.models import BehaviorModel, AgentBehaviorModel, aggregate_event_transitions
|
||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
from .demand import generate_demand
|
||||||
|
|
||||||
|
base_dir = "/home/velocitatem/Documents/Projects/PHANTOM/experiments"
|
||||||
|
human_dir, agent_dir = f"{base_dir}/collected_data/", f"{base_dir}/agents/collected_data/"
|
||||||
|
|
||||||
|
|
||||||
|
def adjust_behavior_to_condition(condition, transition_matrix):
|
||||||
|
# transition matrix just maps probability of eventA to eventB
|
||||||
|
# we enhance this that eventA-productI to eventB-productJ... based on the condition of interest
|
||||||
|
# this is to simulate the impact of demand onto the behavior
|
||||||
|
# NxN -> (N*(P + 1))x(N*(P + 1)) where P is number of products
|
||||||
|
new_transitions = transition_matrix.copy()
|
||||||
|
for col in new_transitions.columns:
|
||||||
|
for product in range(len(condition)):
|
||||||
|
# adjust the transition probability based on the demand condition
|
||||||
|
newname = f"{col}_product{product}"
|
||||||
|
new_transitions[newname] = new_transitions[col] * (condition[product] / np.sum(condition))
|
||||||
|
for row in transition_matrix.index:
|
||||||
|
for product in range(len(condition)):
|
||||||
|
newname = f"{row}_product{product}"
|
||||||
|
new_transitions.loc[newname] = new_transitions.loc[row] * (condition[product] / np.sum(condition))
|
||||||
|
|
||||||
|
return new_transitions.fillna(0.0)
|
||||||
|
|
||||||
|
def sample_behavior(condition, human=True, max_len=40):
|
||||||
|
model = BehaviorModel(human_dir) if human else AgentBehaviorModel(agent_dir)
|
||||||
|
mdp = model.build_MDP()
|
||||||
|
raw_events = aggregate_event_transitions(mdp) # this gets us transtition between events (blind to products or prices)
|
||||||
|
# staet: {state: p} is raw_events we needc a matrix a pivot table
|
||||||
|
events_pivot = pd.DataFrame(raw_events).fillna(0.0)
|
||||||
|
# now adjust the transition matrix based on the condition to get a more informed transition matrix
|
||||||
|
adjusted_transitions = adjust_behavior_to_condition(condition, events_pivot)
|
||||||
|
|
||||||
|
trajectory = [np.random.choice(adjusted_transitions.index)]
|
||||||
|
while len(trajectory) < max_len or 'checkout' in trajectory[-1]:
|
||||||
|
probs = adjusted_transitions.loc[trajectory[-1]].values
|
||||||
|
sample = np.random.choice(adjusted_transitions.columns, p=probs/np.sum(probs) if np.sum(probs) > 0 else None)
|
||||||
|
trajectory.append(sample)
|
||||||
|
return trajectory
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
t=sample_behavior(generate_demand(np.array([10,20,30])), human=True)
|
||||||
|
print(t)
|
||||||
|
t=sample_behavior(generate_demand(np.array([10,20,30])), human=False)
|
||||||
|
print(t)
|
||||||
40
engine/lib/demand.py
Normal file
40
engine/lib/demand.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import numpy as np
|
||||||
|
|
||||||
|
def generate_demand(prices):
|
||||||
|
# assumption 1: each product has an intrinsic valuation drawn from a normal distribution centered at 50
|
||||||
|
product_valuations = np.random.normal(loc=50.0, scale=10.0, size=len(prices))
|
||||||
|
# assumption 2: demand decreases as price increases, following a simple linear model
|
||||||
|
demand = np.maximum(0, product_valuations - prices) # demand cannot be negative
|
||||||
|
demand = demand / np.sum(demand) * 100 # normalize to total demand of 1000 units so demand output is within [0, 100]
|
||||||
|
return demand
|
||||||
|
|
||||||
|
def estimate_demand(trajectories):
|
||||||
|
demand_estimate = {}
|
||||||
|
for traj in trajectories:
|
||||||
|
for event in traj:
|
||||||
|
if 'view_product' in event:
|
||||||
|
product_id = int(event.split('_')[-1].replace('product', ''))
|
||||||
|
demand_estimate[product_id] = demand_estimate.get(product_id, 0) + 1
|
||||||
|
total_views = sum(demand_estimate.values())
|
||||||
|
for product_id in demand_estimate:
|
||||||
|
demand_estimate[product_id] = (demand_estimate[product_id] / total_views) * 100 # normalize to percentage
|
||||||
|
return demand_estimate
|
||||||
|
|
||||||
|
# Example usage
|
||||||
|
if __name__ == "__main__":
|
||||||
|
np.random.seed(42)
|
||||||
|
prices = np.array([20.0, 35.0, 50.0, 65.0])
|
||||||
|
demand = generate_demand(prices)
|
||||||
|
print("Generated Demand:", demand)
|
||||||
|
from .behavior import sample_behavior
|
||||||
|
N, alphat =200, 0.1
|
||||||
|
trajectories = []
|
||||||
|
for _ in range(int(N*(1 - alphat))):
|
||||||
|
trajectories.append(sample_behavior(demand, human=True))
|
||||||
|
for _ in range(int(N*alphat)):
|
||||||
|
trajectories.append(sample_behavior(demand, human=False))
|
||||||
|
demand_estimate = estimate_demand(trajectories)
|
||||||
|
print("Estimated Demand from Behavior:", demand_estimate)
|
||||||
|
delta = {k: demand_estimate.get(k, 0) - demand[i] for i, k in enumerate(range(len(prices)))}
|
||||||
|
delta = np.mean([np.abs(v) for v in delta.values()])
|
||||||
|
print("Demand Delta:", delta)
|
||||||
0
engine/main.py
Normal file
0
engine/main.py
Normal file
@@ -226,6 +226,7 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
agent_model = AgentBehaviorModel(agent_dir)
|
agent_model = AgentBehaviorModel(agent_dir)
|
||||||
agent_mdp = agent_model.build_MDP()
|
agent_mdp = agent_model.build_MDP()
|
||||||
|
print(agent_mdp)
|
||||||
print(f"AGENT... Built MDP: {agent_mdp['num_states']} states, "
|
print(f"AGENT... Built MDP: {agent_mdp['num_states']} states, "
|
||||||
f"{sum(len(t) for t in agent_mdp['transitions'].values())} transitions")
|
f"{sum(len(t) for t in agent_mdp['transitions'].values())} transitions")
|
||||||
if not agent_mdp['states']:
|
if not agent_mdp['states']:
|
||||||
@@ -234,6 +235,9 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
human_evt = aggregate_event_transitions(human_mdp)
|
human_evt = aggregate_event_transitions(human_mdp)
|
||||||
agent_evt = aggregate_event_transitions(agent_mdp)
|
agent_evt = aggregate_event_transitions(agent_mdp)
|
||||||
|
print(agent_evt)
|
||||||
|
|
||||||
|
|
||||||
common = set(human_evt.keys()) & set(agent_evt.keys())
|
common = set(human_evt.keys()) & set(agent_evt.keys())
|
||||||
|
|
||||||
if not common:
|
if not common:
|
||||||
|
|||||||
Reference in New Issue
Block a user