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_presenceisTrue, 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
Trueto 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
xis an iterable or a singleton.- Parameters
x (any) – Object to test for iterable vs. singleton.
- Returns
Trueifxis iterable,Falseif 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
Trueifxis a list,Falseotherwise.- Return type
bool
- is_set(x)[source]¶
Determine whether x is a set.
- Parameters
x (any) – Object to test for set-ness.
- Returns
Trueifxis a set,Falseotherwise.- Return type
bool
- is_dict(x)[source]¶
Determine whether x is a dict.
- Parameters
x (any) – Object to test for dict-ness.
- Returns
Trueifxis a dict,Falseotherwise.- Return type
bool
- is_integer(x)[source]¶
Determine whether
xis an integer. ReturnTrueifxis an int, or a float that evaluates to an integer,Falseotherwise.- Parameters
x (float) – Number to check for integrality.
- Returns
Trueifxis an integer,Falseotherwise.- Return type
bool
- is_numeric_string(s)[source]¶
Determine whether
sis a string that represents a number.- Parameters
s (str) – String to check for integrality.
- Returns
Trueifsrepresents a number,Falseotherwise.- Return type
bool
- is_discrete_distribution(distribution)[source]¶
Check whether the given distribution object is discrete.
Works both for
rv_frozenobjects and for custom distributions (i.e., subclasses ofrv_continuousandrv_discrete).See https://stackoverflow.com/a/61530461/3453768.
- Parameters
distribution (rv_frozen, rv_continuous, or rv_discrete) – The distribution object to check.
- Returns
Trueif the distribution is discrete,Falseotherwise.- Return type
bool
Note
Not reliable if
distributionis not anrv_frozen,rv_discrete, orrv_continuousobject.
- is_continuous_distribution(distribution)[source]¶
Check whether the given distribution object is continuous.
Works both for
rv_frozenobjects and for custom distributions (i.e., subclasses ofrv_continuousandrv_discrete).See https://stackoverflow.com/a/61530461/3453768.
- Parameters
distribution (rv_frozen, rv_continuous, or rv_discrete) – The distribution object to check.
- Returns
Trueif the distribution is continuous,Falseotherwise.- Return type
bool
Note
Not reliable if
distributionis not anrv_frozen,rv_discrete, orrv_continuousobject.
- nearest_dict_value(key_to_search, the_dict)[source]¶
Return the value in
the_dictcorresponding to the key that is closest tokey_to_search.- Parameters
key_to_search (float) – The number to search for among the keys.
the_dict (dict) – The dictionary to search.
- find_nearest(array, values, sorted=False, index={})[source]¶
Determine entries in
arraythat are closest to each of the entries invaluesand return their indices. Neither array needs to be sorted, but ifarrayis sorted andsortedis set toTrue, execution will be faster. In dictionaryindexa map to desired indices can be provided, in which case execution will be even faster for specified values.arrayandvaluesneed 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_listis 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
Trueifiterable_listis a list in which every item is an iterable of the same size or a singleton,Falseotherwise.- Return type
bool
- ensure_list_for_time_periods(x, num_periods, var_name=None)[source]¶
Ensure that
xis 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
xis a singleton, return a list consisting ofnum_periodscopies ofxplus a0in the 0th element.If
xis a list of lengthnum_periods``+1, return ``x.If
xis a list of lengthnum_periods, shift elements to the right by 1 slot, fill the 0th element with 0, and return new list.If
xis a numpy array, convert to list first, then follow above rules.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
xis not a singleton or a list of lengthnum_periodsornum_periods+ 1.
- ensure_list_for_nodes(x, num_nodes, default=None)[source]¶
Ensure that
xis 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
xis a singleton, return a list consisting ofnum_nodescopies ofx.If
xis a list of lengthnum_nodes, returnx.If
xisNoneanddefaultis provided, return a list consisting ofnum_nodescopies ofdefault.If
xisNoneanddefaultis not provided, a list consisting ofnum_nodescopies 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
xisNone.
- Returns
x_new – Node-ified list.
- Return type
list
- Raises
ValueError – If
xis 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, whereais in a key inattribute_dict.build_node_data_dict()is similar to callingensure_dict_for_nodes()for multiple attributes simultaneously.For each attribute
ainattribute_dictkeys,attribute_dict[a]may take one of several forms. For a given node indexnand attributea:If
attribute_dict[a]is a dict, thendata_dict[n][a]is set toattribute_dict[a][n]. Ifnis not a key inattribute_dict[a]thendata_dict[n][a]is set todefault_values[a]if it exists and toNoneotherwise.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], forkinrange(len(node_order_in_lists)).If
attribute_dict[a]isNoneanddefault_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]isNoneanddefault_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, aValueErroris raised.
(Exception: The
demand_listandprobabilitiesattributes ofDemandSourceare 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_listto[0, 1, 2, 3]for all nodes. Butdemand_list=[[0, 1, 2, 3], [0, 1, 2, 3], None, None]will set thedemand_listto[0, 1, 2, 3]for nodes 0 and 1 but toNonefor 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 thekth 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
xis a dict with node indices askeys; if not, create such a dict and return it.If
xis a dict, returnx.If
xis a singleton, return a dict with keys equal tonode_indicesand values all equal tox.If
xis a list with the same length asnode_indices, return a dict with keys equal tonode_indicesand values equal tox.If
xisNoneanddefaultis provided, return a dict with keys equal tonode_indicesand values all equal todefault.If
xisNoneanddefaultis not provided, return a dict with keys equal tonode_indicesand 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 thekth node.)default (float, optional) – Value to use if
xisNone.
- Returns
x_new – Node-ified dict.
- Return type
dict
- Raises
ValueError – If
xis 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.Keys must all be comparable to one another, i.e., all numbers or all strings, with the exception that
Nonekeys are allowed. Special handling is included to handle keys that areNone. (Noneis assumed to come before any other element when sorting in ascending order.)Example:
>>> the_dict = {'a': 5, None: 14, 'b': 7} >>> sort_dict_by_keys(the_dict) [14, 5, 7] >>> sort_dict_by_keys(the_dict, return_values=False) [None, 'a', 'b']
- Parameters
d (dict) – The dict to sort.
ascending (bool, optional) – Sort order.
return_values (bool, optional) – Set to
Trueto return a list of the dict’s values,Falseto return its keys.
- Returns
return_list – List of values or keys of
d, sorted in order of keys ofd.- Return type
list
- sort_nested_dict_by_keys(d, ascending=True, return_values=True)[source]¶
Sort nested dict by its first two levels of keys and return sorted list of values or keys, depending on the value of
return_values. Ifreturn_valuesisFalse, the list returned contains tuples(key1, key2), wherekey1is the key from the outer dict andkey2is the key from the inner dict.Keys must all be comparable to one another, i.e., all numbers or all strings, with the exception that
Nonekeys are allowed. Special handling is included to handle keys that areNone. (Noneis assumed to come before any other element when sorting in ascending order.)Example:
>>> the_dict = {'a': 5, None: 14, 'b': 7} >>> sort_dict_by_keys(the_dict) [14, 5, 7] >>> sort_dict_by_keys(the_dict, return_values=False) [None, 'a', 'b']
- Parameters
d (dict) – The dict to sort.
ascending (bool, optional) – Sort order.
return_values (bool, optional) – Set to
Trueto return a list of the dict’s values,Falseto 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_keytonew_keyindict_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.
- replace_dict_numeric_string_keys(dict_to_change)[source]¶
Replace any key in
dict_to_changethat is a string representing an integer with the integer itself. Return a new dict. Works recursively to replace numeric-string keys in any values indict_to_change, etc.- Parameters
dict_to_change (dict) – The dict.
- Returns
The new dict.
- Return type
dict
- replace_dict_null_keys(dict_to_change)[source]¶
Replace any key in
dict_to_changethat equals the string'null'withNone. Return a new dict. Works recursively to replace'null'’`` keys in any values indict_to_change, etc.- Parameters
dict_to_change (dict) – The dict.
- Returns
The new dict.
- Return type
dict
- compare_unhashable_lists(list1, list2)[source]¶
Determine whether
list1andlist2have the same elements, with the same counts, not necessarily in the same order. ReturnTrueif they do,Falseotherwise.Note
Only use this function for lists of unhashable objects (such as
SupplyChainNodeandSupplyChainProduct). For hashable objects,collections.Counteris faster, e.g.,Counter(list1) == Counter(list2).- Parameters
list1 (list) – The first list to compare.
list2 (list) – The second list to compare.
- Returns
Trueif the two lists have the same elements, with the same counts, not neceessarily in the same order,Falseotherwise.- Return type
bool
- 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
nidentical continuous uniform random variables as anrv_continuousobject.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_continuousobject.- Return type
rv_continuous
- Raises
ValueError – If
nis not an integer.
- sum_of_discrete_uniforms_pmf(n, lo, hi)[source]¶
Calculate pmf of sum of
nidentical 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
nis not an integer.
- sum_of_discrete_uniforms_distribution(n, lo, hi)[source]¶
Return distribution of sum of
nidentical discrete uniform random variables as anrv_continuousobject.- 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_discreteobject.- Return type
rv_discrete
- Raises
ValueError – If
nis not an integer.
- sum_of_discretes_distribution(n, lo, hi, p)[source]¶
Return distribution of convolution of
nidentical discrete random variables as anrv_discreteobject.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_discreteobject.- Return type
rv_discrete
- Raises
ValueError – If
n,lo, orhiare not integers.ValueError – If
pdoes 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
Noneto not round at all.
- serialize_set(obj)[source]¶
Serialize a set by converting it to a dict of the form
{'type': 'set', 'elements': elements}, whereelementsare the elements of the set.This is used for serializing objects so they can be saved in JSON format. To use:
json.dump(json_contents, file, default=serialize_set).- Parameters
obj (Any) – The object to serialize.
- Returns
Dictionary representation of
obj, ifobjis a set.- Return type
dict
- deserialize_set(obj)[source]¶
Deserialize a set of the form
{'type': 'set', 'elements': elements}by converting it to a set of the form{elements}.This is used for deserializing objects to they can be loaded from JSON format. To use:
json.load(file, object_hook=deserialize_set).- Parameters
obj (Any) – The object to deserialize.
- Returns
Set representation of
obj, ifobjis a dict of the appropriate form.- Return type
set