From 6e06081d60a01909f7bf51c1a8aa7abe8f2d9b62 Mon Sep 17 00:00:00 2001 From: Daniel Rosel Date: Wed, 28 Jan 2026 16:09:28 +0100 Subject: [PATCH] porting to better --- engine/engine.py | 66 ++++++++++++++++++++++++++++++++++++++++++++ engine/lib/demand.py | 8 ++++-- engine/main.py | 0 engine/wrapper.py | 5 ++++ 4 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 engine/engine.py delete mode 100644 engine/main.py create mode 100644 engine/wrapper.py diff --git a/engine/engine.py b/engine/engine.py new file mode 100644 index 0000000..e304aeb --- /dev/null +++ b/engine/engine.py @@ -0,0 +1,66 @@ +from sys import platform +import numpy as np +from .lib.demand import generate_demand, estimate_demand +from .lib.behavior import sample_behavior +from logging import INFO, getLogger +logger = getLogger(__name__) +logger.setLevel(INFO) + + + +class MarketEngine(): + def __init__(self, + alpha = 0.5, + N = 100, + demand_distribution = (50, 10), + demand_sampling_function = np.random.normal): + self.Nagents = int(N*alpha) + self.Nhumans = int(N*(1-alpha)) + self.demand = (demand_sampling_function, demand_distribution) + + def act(self, prices): + demand = generate_demand(prices, *self.demand) + sample_n = lambda n, human: [sample_behavior(demand, human=human) for _ in range(n)] + human_t, agent_t = sample_n(100, True), sample_n(100, False) + trajectories = human_t + agent_t + demand_estimate = estimate_demand(trajectories) + return demand_estimate + + def measure(self): + pass + +class PricingEngine(): + def __init__(self, + ) -> None: + pass + + def act(self, demand): + return np.random.uniform(low=25, high=100, size=10) + + + +class Limbo(): + def __init__(self, + platform, + market + ) -> None: + self.platform_turn = True + self.platform = platform + self.market = market + self.output = None + + def step(self): + # we could code golf this a little bit + if self.platform_turn: + self.output = self.platform.act(self.output) + else: + self.output = self.market.act(self.output) + print(self.output) + self.platform_turn = not self.platform_turn + +if __name__ == "__main__": + platform = PricingEngine() + market = MarketEngine() + limbo = Limbo(platform, market) + for _ in range(10): + limbo.step() diff --git a/engine/lib/demand.py b/engine/lib/demand.py index 52e28e7..687afe8 100644 --- a/engine/lib/demand.py +++ b/engine/lib/demand.py @@ -1,11 +1,15 @@ +import logging import numpy as np +from logging import getLogger +logger = getLogger(__name__) -def generate_demand(prices): +def generate_demand(prices, distribution_method = np.random.normal, distribution_params = (50.0, 10.0)): # 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)) + product_valuations = distribution_method(*distribution_params, 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] + logger.info(f"Generated demand for prices {prices}: {demand} with valuations from distribution {distribution_params}") return demand def estimate_demand(trajectories): diff --git a/engine/main.py b/engine/main.py deleted file mode 100644 index e69de29..0000000 diff --git a/engine/wrapper.py b/engine/wrapper.py new file mode 100644 index 0000000..1cf5815 --- /dev/null +++ b/engine/wrapper.py @@ -0,0 +1,5 @@ +import gymnasium as gym +from gymnasium import spaces +from engine import Limbo + +class PHANTOM(gym.Env, Limbo):