class ConfigurableGenerator(CustomerGeneratorPort): """ Adaptador (output): genera clientes utilizando distribuciones estadísticas configurables. Permite simular llegadas usando procesos de Poisson (distribución exponencial de tiempos entre llegadas) o intervalos fijos. """ def __init__(self, config: Dict[str, Any]): self.config = config # Tasa promedio de llegada de clientes por unidad de tiempo (lambda) self.arrival_rate = config.get("arrival_rate", 1.0) # Tipo de distribución para las llegadas ('exponential' para procesos de Poisson, o 'fixed' para fijos) self.arrival_dist = config.get("arrival_dist", "exponential") # Tiempo promedio requerido para atender a un cliente (mu) self.service_mean = config.get("service_mean", 5.0) # Tipo de distribución para la duración del servicio ('exponential', 'normal', o 'constant') self.service_dist = config.get("service_dist", "exponential") # Desviación estándar utilizada únicamente cuando la distribución del servicio es 'normal' self.service_stddev = config.get("service_stddev", 1.0) # Probabilidades de asignar cada nivel de prioridad al generar un cliente (Alta, Media, Baja) self.priority_weights = config.get("priority_weights", [0.1, 0.3, 0.6])
def get_next_arrival_interval(self) -> float: """ Calcula y devuelve el tiempo que transcurrirá hasta la llegada del próximo cliente. Utiliza distribución exponencial si está configurado como Poisson, o tiempos fijos en caso contrario. """ if self.arrival_dist == "exponential": # Para llegadas de Poisson, el tiempo entre llegadas sigue una distribución exponencial return random.expovariate(self.arrival_rate) elif self.arrival_dist == "fixed": # Si el tiempo es fijo, es simplemente la inversa de la tasa de llegada return 1.0 / self.arrival_rate else: return random.expovariate(self.arrival_rate)
Exponential (Poisson)
Fixed
# For λ = 1.0 customers/secondinterval = random.expovariate(1.0)# Returns random value with mean = 1.0 second# Examples: 0.3s, 1.8s, 0.05s, 2.7s (highly variable!)
Characteristics:
Mean = 1/λ
Variance = 1/λ²
Memoryless property
Models random, unpredictable arrivals
# For λ = 1.0 customers/secondinterval = 1.0 / 1.0 # Always 1.0 second# Customers arrive exactly every 1 second
def get_next_customer_attributes(self) -> Tuple[int, str]: """ Selecciona aleatoriamente los atributos de un nuevo cliente que acaba de llegar. Elige su prioridad basada en los pesos configurados y asigna un tipo de transacción uniforme. """ # Elige la prioridad del cliente según las ponderaciones (pesos) definidas prio = random.choices( [Priority.HIGH.value, Priority.MEDIUM.value, Priority.LOW.value], weights=self.priority_weights, k=1 )[0] # Selecciona aleatoriamente un tipo de transacción bancaria txn = random.choice(list(TransactionType)).value return prio, txn
Each arriving customer gets:
Priority: Randomly chosen based on priority_weights (e.g., [0.1, 0.3, 0.6])
Transaction type: Uniformly random (DEPOSIT, WITHDRAWAL, etc.)
Service time: Generated separately based on service_dist
def get_service_time(self) -> float: """ Calcula y devuelve la duración del servicio que requerirá un nuevo cliente en la ventanilla. Soporta distribuciones exponenciales, normales (con límite inferior > 0) y constantes. """ if self.service_dist == "exponential": return random.expovariate(1.0 / self.service_mean) elif self.service_dist == "normal": time = random.gauss(self.service_mean, self.service_stddev) return max(1.0, time) # Asegura que el tiempo de servicio resultante sea siempre positivo elif self.service_dist == "constant": return self.service_mean else: return self.service_mean
Exponential Service
Normal Service
Constant Service
service_config = { "service_mean": 5.0, "service_dist": "exponential"}# Mean = 5.0 seconds, high variability (CV = 1)# Some customers take 1s, others 15s
service_config = { "service_mean": 5.0, "service_dist": "normal", "service_stddev": 1.0}# Mean = 5.0s, StdDev = 1.0s# Most customers take 4-6s (within 1σ)# Minimum enforced at 1.0s
service_config = { "service_mean": 5.0, "service_dist": "constant"}# Every customer takes exactly 5.0 seconds# No variability
Mean inter-arrival time = 1/arrival_rate = 1.0 second
NOT the same as “arrivals every 1 second” (that’s deterministic)
Expecting uniform spacing with Poisson
Poisson arrivals are bursty - clusters and gaps are normal!If you want uniform spacing, use "arrival_dist": "fixed"
Ignoring variance in service times
Even if mean arrival and service rates suggest stability, high variance can cause issues.Use normal distribution with low stddev for more predictable behavior.