diff --git a/simopt/input_models.py b/simopt/input_models.py index b640f751..066f2adc 100644 --- a/simopt/input_models.py +++ b/simopt/input_models.py @@ -3,9 +3,9 @@ import bisect import itertools import math -import random from abc import abstractmethod from collections.abc import Sequence +from random import Random from typing import ParamSpec, Protocol, TypeVar P = ParamSpec("P") @@ -15,9 +15,9 @@ class InputModel(Protocol[P, R]): """Abstract base for input models used by simulations.""" - rng: random.Random | None = None + rng: Random | None = None - def set_rng(self, rng: random.Random) -> None: + def set_rng(self, rng: Random) -> None: """Attach a Python RNG to the input model. Args: diff --git a/simopt/models/amusementpark.py b/simopt/models/amusementpark.py index f2718037..1edc8503 100644 --- a/simopt/models/amusementpark.py +++ b/simopt/models/amusementpark.py @@ -478,9 +478,10 @@ def set_completion(i: int, new_time: float) -> None: cumulative_util = [cumulative_util[i] / time_open for i in attraction_range] # Calculate responses from simulation data. + percent_departed = total_departed / total_visitors if total_visitors else 0 responses = { "total_departed": total_departed, - "percent_departed": total_departed / total_visitors, + "percent_departed": percent_departed, "average_number_in_system": time_average / time_open, "attraction_utilization_percentages": cumulative_util, } diff --git a/simopt/models/chessmm.py b/simopt/models/chessmm.py index a08f5513..faadc3bd 100644 --- a/simopt/models/chessmm.py +++ b/simopt/models/chessmm.py @@ -2,7 +2,7 @@ from __future__ import annotations -import random +from random import Random from typing import Annotated, ClassVar, Final import numpy as np @@ -111,7 +111,7 @@ class ChessAvgDifferenceConfig(BaseModel): class EloInputModel(InputModel): """Input model for player Elo ratings.""" - rng: random.Random | None = None + rng: Random | None = None def random( self, mean: float, std: float, min_rating: float, max_rating: float diff --git a/simopt/models/cntnv.py b/simopt/models/cntnv.py index 4f17a519..89819313 100644 --- a/simopt/models/cntnv.py +++ b/simopt/models/cntnv.py @@ -2,7 +2,7 @@ from __future__ import annotations -import random +from random import Random from typing import Annotated, ClassVar, Self import numpy as np @@ -128,7 +128,7 @@ class CntNVMaxProfitConfig(BaseModel): class DemandInputModel(InputModel): """Input model for Burr Type XII demand.""" - rng: random.Random | None = None + rng: Random | None = None def random(self, burr_c: float, burr_k: float) -> float: # noqa: D102 # Generate random demand according to Burr Type XII distribution. diff --git a/simopt/models/dualsourcing.py b/simopt/models/dualsourcing.py index 5e4e1401..784e8e1f 100644 --- a/simopt/models/dualsourcing.py +++ b/simopt/models/dualsourcing.py @@ -2,7 +2,7 @@ from __future__ import annotations -import random +from random import Random from typing import Annotated, ClassVar, Self import numpy as np @@ -166,7 +166,7 @@ class DualSourcingMinCostConfig(BaseModel): class DemandInputModel(InputModel): """Input model for daily demand.""" - rng: random.Random | None = None + rng: Random | None = None def random(self, mu: float, sigma: float) -> int: # noqa: D102 def round_and_clamp_non_neg(x: float | int) -> int: diff --git a/simopt/models/dynamnews.py b/simopt/models/dynamnews.py index b6612204..ccedf04d 100644 --- a/simopt/models/dynamnews.py +++ b/simopt/models/dynamnews.py @@ -3,7 +3,7 @@ from __future__ import annotations import math -import random +from random import Random from typing import Annotated, ClassVar, Final, Self import numpy as np @@ -155,7 +155,7 @@ class DynamNewsMaxProfitConfig(BaseModel): class Utility(InputModel): """Input model for customer utility sampling.""" - rng: random.Random | None = None + rng: Random | None = None def _gumbelvariate(self, mu: float, beta: float) -> float: assert self.rng is not None diff --git a/simopt/models/facilitysizing.py b/simopt/models/facilitysizing.py index 276245b5..48834921 100644 --- a/simopt/models/facilitysizing.py +++ b/simopt/models/facilitysizing.py @@ -2,7 +2,7 @@ from __future__ import annotations -import random +from random import Random from typing import Annotated, ClassVar, Final, Self import numpy as np @@ -204,7 +204,7 @@ def _validate_problem(self) -> Self: class DemandInputModel(InputModel): """Input model for multivariate normal demand at facilities.""" - rng: random.Random | None = None + rng: Random | None = None def _mvnormalvariate( self, diff --git a/simopt/models/hotel.py b/simopt/models/hotel.py index 6f0fda6d..69150382 100644 --- a/simopt/models/hotel.py +++ b/simopt/models/hotel.py @@ -307,7 +307,7 @@ def replicate(self) -> tuple[dict, dict]: total_revenue = 0 # Generate interarrival times - arr_bound = 10 * round(168 * np.sum(f_lambda)) + arr_bound = 10 * round(168 * sum(f_lambda)) arr_time = np.array( [ [self.arrival_model.random(f_lambda[i]) for _ in range(arr_bound)] diff --git a/simopt/models/ironore.py b/simopt/models/ironore.py index 3a73b8cd..8fd0d141 100644 --- a/simopt/models/ironore.py +++ b/simopt/models/ironore.py @@ -6,8 +6,8 @@ from __future__ import annotations -import random from math import copysign, sqrt +from random import Random from typing import Annotated, ClassVar, Self import numpy as np @@ -202,7 +202,7 @@ class IronOreMaxRevConfig(BaseModel): class MovementInputModel(InputModel): """Input model for mining movement and price shocks.""" - rng: random.Random | None = None + rng: Random | None = None def random(self, mean: float, std: float) -> float: # noqa: D102 assert self.rng is not None diff --git a/simopt/models/network.py b/simopt/models/network.py index 4d56a24f..25425cfb 100644 --- a/simopt/models/network.py +++ b/simopt/models/network.py @@ -2,8 +2,8 @@ from __future__ import annotations -import random from enum import IntEnum +from random import Random from typing import Annotated, ClassVar, Final, Self import numpy as np @@ -215,7 +215,7 @@ class NetworkMinTotalCostConfig(BaseModel): class RouteInputModel(InputModel): """Input model for routing choices in the network.""" - rng: random.Random | None = None + rng: Random | None = None def random(self, choices: list[int], weights: list[float], k: int) -> list[int]: # noqa: D102 assert self.rng is not None diff --git a/simopt/models/tableallocation.py b/simopt/models/tableallocation.py index 5d6fb5c1..7f9c6336 100644 --- a/simopt/models/tableallocation.py +++ b/simopt/models/tableallocation.py @@ -5,7 +5,7 @@ import bisect import itertools from collections.abc import Sequence -from typing import Annotated, ClassVar, Self +from typing import Annotated, ClassVar, Self, cast import numpy as np from pydantic import BaseModel, Field, model_validator @@ -256,9 +256,12 @@ def fast_weighted_choice( # Pass through all arrivals of groups to the restaurants. for n in range(n_arrivals): # Determine group size. - group_size = self.group_size_model.random( - population=group_size_options, - weights=f_lambda, + group_size = cast( + int, + self.group_size_model.random( + population=group_size_options, + weights=f_lambda, + ), ) # Find smallest table size to start search. diff --git a/ty.toml b/ty.toml index 44f2c20f..b3261959 100644 --- a/ty.toml +++ b/ty.toml @@ -19,15 +19,6 @@ exclude = [ "simopt/gui/new_experiment_window.py", "simopt/gui/plot_window.py", "simopt/model.py", - "simopt/models/amusementpark.py", - "simopt/models/chessmm.py", - "simopt/models/cntnv.py", - "simopt/models/dualsourcing.py", - "simopt/models/dynamnews.py", - "simopt/models/facilitysizing.py", - "simopt/models/ironore.py", - "simopt/models/network.py", - "simopt/models/tableallocation.py", "simopt/plot_type.py", "simopt/plots", "simopt/problem.py",