helpers
Module¶
Overview¶
The helpers
module contains helper functions that are used by functions throughout the
Stockpyl package.
API Reference¶
- min_of_dict(d)[source]¶
Determine min value of a dict and return min and argmin (key).
Values must be numeric.
- Parameters
d (dict) – The dict.
- Returns
min_value (float) – Minimum value in dict.
min_key (any) – Key that attains minimum value.
- Raises
TypeError – If dict contains a non-numeric value.
- dict_match(d1, d2, require_presence=False, rel_tol=1e-09, abs_tol=0.0)[source]¶
Check whether two dicts have equal keys and values.
A missing key is treated as 0 if the key is present in the other dict, unless
require_presence
isTrue
, in which case the dict must have the key to count as a match.- Parameters
d1 (node) – First dict for comparison.
d2 (node) – Second dict for comparison.
require_presence (bool, optional) – Set to
True
to require dicts to have the same keys, orFalse
(default) to treat missing keys as 0s.rel_tol (float) – Relative tolerance.
abs_tol (float) – Absolute tolerance.
- is_iterable(x)[source]¶
Determine whether
x
is an iterable or a singleton.- Parameters
x (any) – Object to test for iterable vs. singleton.
- Returns
True
ifx
is iterable,False
if it is a singleton.- Return type
bool
- is_list(x)[source]¶
Determine whether x is a list.
- Parameters
x (any) – Object to test for list-ness.
- Returns
True
ifx
is a list,False
otherwise.- Return type
bool
- is_integer(x)[source]¶
Determine whether
x
is an integer. ReturnFalse
ifx
is not a float, or is a non-integer float, or is an int.- Parameters
x (float) – Number to check for integrality.
- Returns
True
ifx
is an integer,False
otherwise.- Return type
bool
- is_discrete_distribution(distribution)[source]¶
Check whether the given distribution object is discrete.
Works both for
rv_frozen
objects and for custom distributions (i.e., subclasses ofrv_continuous
andrv_discrete
).See https://stackoverflow.com/a/61530461/3453768.
- Parameters
distribution (rv_frozen, rv_continuous, or rv_discrete) – The distribution object to check.
- Returns
True
if the distribution is discrete,False
otherwise.- Return type
bool
Note
Not reliable if
distribution
is not anrv_frozen
,rv_discrete
, orrv_continuous
object.
- is_continuous_distribution(distribution)[source]¶
Check whether the given distribution object is continuous.
Works both for
rv_frozen
objects and for custom distributions (i.e., subclasses ofrv_continuous
andrv_discrete
).See https://stackoverflow.com/a/61530461/3453768.
- Parameters
distribution (rv_frozen, rv_continuous, or rv_discrete) – The distribution object to check.
- Returns
True
if the distribution is continuous,False
otherwise.- Return type
bool
Note
Not reliable if
distribution
is not anrv_frozen
,rv_discrete
, orrv_continuous
object.
- find_nearest(array, values, sorted=False, index={})[source]¶
Determine entries in
array
that are closest to each of the entries invalues
and return their indices. Neither array needs to be sorted, but ifarray
is sorted andsorted
is set toTrue
, execution will be faster. In dictionaryindex
a map to desired indices can be provided, in which case execution will be even faster for specified values.array
andvalues
need not be the same length.- Parameters
array (ndarray) – The array to search for values in.
values (ndarray) – The array whose values should be searched for in the other array.
sorted (bool, optional) – If
True
, treats array as sorted, which will make the function execute faster.index (dict, optional) – A dictionary from values to indices, which will make the function execute even faster for given values.
- Returns
ind – Array of indices.
- Return type
ndarray
- check_iterable_sizes(iterable_list)[source]¶
Check whether
iterable_list
is a list in which every item is an iterable of the same size or a singleton.Examples:
>>> check_iterable_sizes([[5, 3, 1], ('a', 'b', 'c'), 7]) True >>> check_iterable_sizes([[5, 3, 1], ('a', 'b'), 7]) False
- Parameters
iterable_list (list) – List to check.
- Returns
True
ifiterable_list
is a list in which every item is an iterable of the same size or a singleton,False
otherwise.- Return type
bool
- ensure_list_for_time_periods(x, num_periods, var_name=None)[source]¶
Ensure that
x
is a list suitable for time-period indexing; if not, create such a list and return it.“Suitable for time-period indexing” means that it has length
num_periods
+ 1, and the 0th element is ignored.If
x
is a singleton, return a list consisting ofnum_periods
copies ofx
plus a0
in the 0th element.If
x
is a list of lengthnum_periods``+1, return ``x
.If
x
is a list of lengthnum_periods
, shift elements to the right by 1 slot, fill the 0th element with 0, and return new list.Otherwise, raise a
ValueError
.
Examples:
>>> ensure_list_for_time_periods(5, 3) [0, 5, 5, 5] >>> ensure_list_for_time_periods([0, 5, 2, 1], 4) [0, 0, 5, 2, 1] >>> ensure_list_for_time_periods([5, 2, 1, 3, 2], 4) [5, 2, 1, 3, 2] >>> ensure_list_for_time_periods([0, 5, 2, 1, 5], 3) Traceback (most recent call last): ... ValueError: x must be a singleton or a list of length num_periods or num_periods+1
- Parameters
x (float or list) – Object to time-period-ify.
num_periods (int) – Number of time periods.
var_name (str, optional) – Variable name to use in generating error messages, if desired. Useful for offloading the type-checking to this function rather than doing it in the calling function.
- Returns
x_new – Time-period-ified list.
- Return type
list
- Raises
ValueError – If
x
is not a singleton or a list of lengthnum_periods
ornum_periods
+ 1.
- ensure_list_for_nodes(x, num_nodes, default=None)[source]¶
Ensure that
x
is a list suitable for node indexing; if not, create such a list and return it.“Suitable for node indexing” means that it has length
num_nodes
.If
x
is a singleton, return a list consisting ofnum_nodes
copies ofx
.If
x
is a list of lengthnum_nodes
, returnx
.If
x
isNone
anddefault
is provided, return a list consisting ofnum_nodes
copies ofdefault
.If
x
isNone
anddefault
is not provided, a list consisting ofnum_nodes
copies ofNone
.Otherwise, raise a
ValueError
.
Examples:
>>> ensure_list_for_nodes(5, 3) [5, 5, 5] >>> ensure_list_for_nodes([0, 5, 2, 1], 4) [0, 5, 2, 1] >>> ensure_list_for_nodes([0, 5, 2, 1], 3) Traceback (most recent call last): ... ValueError: x must be a singleton, a list of length num_nodes, or None
- Parameters
x (float or list) – Object to node-ify.
num_nodes (int) – Number of nodes.
default (float, optional) – Value to use if
x
isNone
.
- Returns
x_new – Node-ified list.
- Return type
list
- Raises
ValueError – If
x
is not a singleton, a list of lengthnum_nodes
, orNone
.
- build_node_data_dict(attribute_dict, node_order_in_lists, default_values={})[source]¶
Build a dict of dicts containing data for all nodes and for one or more attributes. The dict returned,
data_dict
, is keyed by the node indices.data_dict[n]
is a dict of data for the node with indexn
, anddata_dict[n][a]
is the value of attributea
, wherea
is in a key inattribute_dict
.build_node_data_dict()
is similar callingensure_dict_for_nodes()
for multiple attributes simultaneously.For each attribute
a
inattribute_dict
keys,attribute_dict[a]
may take one of several forms. For a given node indexn
and attributea
:If
attribute_dict[a]
is a dict, thendata_dict[n][a]
is set toattribute_dict[a][n]
. Ifn
is not a key inattribute_dict[a]
thendata_dict[n][a]
is set todefault_values[a]
if it exists and toNone
otherwise.If
attribute_dict[a]
is a singleton, thendata_dict[n][a]
is set toattribute_dict[a]
.If
attribute_dict[a]
is a list with the same length asnode_order_in_lists
, then the values in the list are assumed to correspond to the node indices in the order they are specified innode_order_in_lists
. That is,attribute_dict[a][k]
is placed indata_dict[node_order_in_lists[k]][a]
, fork
inrange(len(node_order_in_lists))
.If
attribute_dict[a]
isNone
anddefault_values[a]
is provided,data_dict[n][a]
is set todefault_values[a]
. (This is useful for setting default values for attributes that are passed without knowing whether data is provided for them.)If
attribute_dict[a]
isNone
anddefault_values[a]
is not provided,data_dict[n][a]
is set toNone
.If
attribute_dict[a]
is a list that does not have the same length asnode_order_in_lists
, aValueError
is raised.
(Exception: The
demand_list
andprobabilities
attributes ofDemandSource
are lists, and are treated as singletons for the purposes of the rules above, unless they contain other lists, in which case they are treated as normal. For example,attribute_dict['demand_list'] = [0, 1, 2, 3]
will set thedemand_list
to[0, 1, 2, 3]
for all nodes. Butdemand_list=[[0, 1, 2, 3], [0, 1, 2, 3], None, None]
will set thedemand_list
to[0, 1, 2, 3]
for nodes 0 and 1 but toNone
for nodes 2 and 3.)- Parameters
attribute_dict (dict) – Dict whose keys are strings (representing node attributes) and whose values are dicts, lists, and/or singletons specifying the values of the attributes for the nodes.
node_order_in_lists (list) – List of node indices in the order in which the nodes are listed in any attributes that are lists. (
node_order_in_lists[k]
is the index of thek
th node.)default_values (dict) – Dict whose keys are strings (in
attribute_dict.keys()
) and whose values are the default values to use if the attribute is not provided.
- Returns
data_dict – The data dict.
- Return type
dict
- Raises
ValueError – If
attribute_dict[a]
is a list whose length does not equal that ofnode_order_in_lists
.
Example:
>>> attribute_dict = {} >>> attribute_dict['local_holding_cost'] = 1 >>> attribute_dict['stockout_cost'] = [10, 8, 0] >>> attribute_dict['demand_mean'] = {1: 0, 3: 50} >>> attribute_dict['lead_time'] = None >>> attribute_dict['processing_time'] = None >>> node_order_in_lists = [3, 2, 1] >>> default_values = {'lead_time': 0, 'demand_mean': 99} >>> data_dict = build_node_data_dict(attribute_dict, node_order_in_lists, default_values) >>> data_dict[1] {'local_holding_cost': 1, 'stockout_cost': 0, 'demand_mean': 0, 'lead_time': 0, 'processing_time': None} >>> data_dict[2] {'local_holding_cost': 1, 'stockout_cost': 8, 'demand_mean': 99, 'lead_time': 0, 'processing_time': None} >>> data_dict[3] {'local_holding_cost': 1, 'stockout_cost': 10, 'demand_mean': 50, 'lead_time': 0, 'processing_time': None}
- ensure_dict_for_nodes(x, node_indices, default=None)[source]¶
Ensure that
x
is a dict with node indices askeys
; if not, create such a dict and return it.If
x
is a dict, returnx
.If
x
is a singleton, return a dict with keys equal tonode_indices
and values all equal tox
.If
x
is a list with the same length asnode_indices
, return a dict with keys equal tonode_indices
and values equal tox
.If
x
isNone
anddefault
is provided, return a dict with keys equal tonode_indices
and values all equal todefault
.If
x
isNone
anddefault
is not provided, return a dict with keys equal tonode_indices
and values all equal toNone
.Otherwise, raise a
ValueError
.
- Parameters
x (dict, float, or list) – Object to node-ify.
node_indices (list) – List of node indices. (
node_indices[k]
is the index of thek
th node.)default (float, optional) – Value to use if
x
isNone
.
- Returns
x_new – Node-ified dict.
- Return type
dict
- Raises
ValueError – If
x
is not a dict, a singleton, a list with the same length asnode_indices
, orNone
.
Examples:
>>> ensure_dict_for_nodes(5, [0, 1, 2]) {0: 5, 1: 5, 2: 5} >>> ensure_dict_for_nodes([0, 5, 2], [0, 1, 2]) {0: 0, 1: 5, 2: 2} >>> ensure_list_for_nodes([0, 5, 2, 1], [0, 1, 2]) Traceback (most recent call last): ... ValueError: x must be a singleton, dict, list with the same length as node_indices, or None
- sort_dict_by_keys(d, ascending=True, return_values=True)[source]¶
Sort dict by keys and return sorted list of values or keys, depending on the value of
return_values
.Special handling is included to handle keys that might be
None
. (None
is assumed to come before any other element when sorting in ascending order.)- Parameters
d (dict) – The dict to sort.
ascending (bool, optional) – Sort order.
return_values (bool, optional) – Set to
True
to return a list of the dict’s values,False
to return its keys.
- Returns
return_list – List of values or keys of
d
, sorted in order of keys ofd
.- Return type
list
- change_dict_key(dict_to_change, old_key, new_key)[source]¶
Change
old_key
tonew_key
indict_to_change
(in place). New key/value pair will appear at end of dict.- Parameters
dict_to_change (dict) – The dict.
old_key – The key to be changed.
new_key – The key to change to.
- Raises
KeyError – If
dict_to_change[old_key]
is undefined.
- convolve_many(arrays)[source]¶
Convolve a list of 1-dimensional float arrays together, using fast Fourier transforms (FFTs). The arrays need not have the same length, but each array should have length at least 1.
If the arrays represent pmfs of discrete random variables \(X_1,\ldots,X_n\), then the output represents the pmf of \(X_1+\cdots+X_n\). Assuming the possible values of all of the random variables are equally spaced with spacing \(s\), the possible values of \(X_1+\cdots+X_n\) corresponding to the output are \(\sum_i\min X_i,\ldots,\sum_i \max X_i\), with spacing \(s\).
Code is adapted from https://stackoverflow.com/a/29236193/3453768.
- Parameters
arrays (list of 1-dimensional float arrays) – The arrays to convolve.
- Returns
convolution – Array of elements in the convolution.
- Return type
array
Example: Let \(X_1 = \{0, 1, 2\}\) with probabilities \([0.6, 0.3, 0.1]\), \(X_2 = \{0, 1, 2\}\) with probabilities \([0.5, 0.4, 0.1]\), \(X_3 = \{0, 1\}\) with probabilities \([0.3, 0.7]\), and \(X_4 = 0\) with probability \(1\).
>>> convolve_many([[0.6, 0.3, 0.1], [0.5, 0.4, 0.1], [0.3, 0.7], [1.0]]) array([0.09 , 0.327, 0.342, 0.182, 0.052, 0.007])
In other words, \(X_1+\cdots+X_4 = \{0, 1, \ldots, 5\}\) with probabilities \([0.09 , 0.327, 0.342, 0.182, 0.052, 0.007]\).
- irwin_hall_cdf(x, n)[source]¶
Return cdf of Irwin-Hall distribution, i.e., distribution of sum of
n
\(U[0,1]\) random variables.See https://en.wikipedia.org/wiki/Irwin%E2%80%93Hall_distribution.
- Parameters
x (float) – Argument of cdf function.
n (int) – Number of \(U[0,1]\) random variables in the sum.
- Returns
F – The cdf of
x
.- Return type
float
- sum_of_continuous_uniforms_distribution(n, lo=0, hi=1)[source]¶
Return distribution of sum of
n
identical continuous uniform random variables as anrv_continuous
object.If
lo
= 0 andhi
= 1, this distribution is the Irwin-Hall distribution.- Parameters
n (int) – Number of uniform random variables in the sum.
lo (float, optional) – Lower bound of uniform distribution. Default = 0.
hi (float, optional) – Upper bound of uniform distribution. Default = 1.
- Returns
distribution – The
rv_continuous
object.- Return type
rv_continuous
- Raises
ValueError – If
n
is not an integer.
- sum_of_discrete_uniforms_pmf(n, lo, hi)[source]¶
Calculate pmf of sum of
n
identical discrete uniform random variables. Return values as dict.Adapted from https://stackoverflow.com/a/69842911/3453768.
- Parameters
n (int) – Number of uniform random variables in the sum.
lo (int) – Lower bound of uniform distribution.
hi (int) – Upper bound of uniform distribution.
- Returns
Dictionary of pmf values.
- Return type
dict
- Raises
ValueError – If
n
is not an integer.
- sum_of_discrete_uniforms_distribution(n, lo, hi)[source]¶
Return distribution of sum of
n
identical discrete uniform random variables as anrv_continuous
object.- Parameters
n (int) – Number of uniform random variables in the sum.
lo (int) – Lower bound of uniform distribution.
hi (int) – Upper bound of uniform distribution.
- Returns
distribution – The
rv_discrete
object.- Return type
rv_discrete
- Raises
ValueError – If
n
is not an integer.
- sum_of_discretes_distribution(n, lo, hi, p)[source]¶
Return distribution of convolution of
n
identical discrete random variables as anrv_discrete
object.The random variables must have support
lo
,lo
+ 1, …,hi
. (The convolution will have supportn * lo
,n * lo
+ 1, …,n * hi
).- Parameters
n (int) – Number of uniform random variables in the sum.
lo (int) – Smallest value of the support of the random variable.
hi (int) – Largest value of the support of the random variable.
p (list) – Probabilities of each of the values.
- Returns
distribution – The
rv_discrete
object.- Return type
rv_discrete
- Raises
ValueError – If
n
,lo
, orhi
are not integers.ValueError – If
p
does not have lengthhi - lo + 1
.
- round_dict_values(the_dict, round_type=None)[source]¶
Round the values in a dict. Return a new dict.
- Parameters
the_dict (dict) – The dict to round
round_type (string, optional) – Set to ‘up’ to round all values up to next larger integer, ‘down’ to round down, ‘nearest’ to round to nearest integer, or
None
to not round at all.