supply_chain_network Module

Overview

This module contains the SupplyChainNetwork class, which is a network consisting of one or more nodes and, optionally, one or more products. The network, nodes, and products together specify a problem instance.

Note

The terms “node” and “stage” are used interchangeably in the documentation.

Note

The notation and references (equations, sections, examples, etc.) used below refer to Snyder and Shen, Fundamentals of Supply Chain Theory (FoSCT), 2nd edition (2019).

A SupplyChainNetwork is used primarily for multi-echelon inventory optimization (MEIO) or simulation. Most data for the problem instance is specified in the SupplyChainNode and SupplyChainProduct objects contained within the SupplyChainNetwork, rather than in the network itself.

API Reference

class SupplyChainNetwork(**kwargs)[source]

The SupplyChainNetwork class contains one or more nodes, each represented by a SupplyChainNode object.

period

The current period. Used for simulation.

Type

int

problem_specific_data

Placeholder for object that is used to provide data for specific problem types.

Type

object

max_max_replenishment_time

Largest value of max_replenishment_time among all nodes in the network. Used by gsm_tree module.

Type

int

property nodes

List of all nodes in the network, as SupplyChainNode objects. Read only.

property node_indices

List of indices of all nodes in the network. Read only.

property nodes_by_index

A dict containing nodes in the network. The keys of the dict are node indices and the values are the corresponding SupplyChainNode objects. For example, self.nodes_by_index[4] is a SupplyChainNode object with index 4. Read only.

property products

List of all products in the network, as SupplyChainProduct objects. Includes products that have been explicitly added to the network via add_product() as well as products that are handled by the nodes in the network. Read only.

property product_indices

List of indices of all products in the network. Includes products that have been explicitly added to the network via add_product() as well as products that are handled by the nodes in the network. Read only.

property products_by_index

A dict containing products in the network. Includes products that have been explicitly added to the network via add_product() as well as products that are handled by the nodes in the network.

The keys of the dict are product indices and the values are the corresponding SupplyChainProduct objects. For example, self.products_by_index[4] returns a SupplyChainProduct object for the product with index 4.

Includes “dummy products” that are added internally to nodes that do not have a SupplyChainProduct object added. Dummy products are identifiable as such by their index, which is always negative.

Read only.

property source_nodes

List of all source nodes, i.e., all nodes that have no predecessors, as SupplyChainNode objects. Read only.

property sink_nodes

List of all sink nodes, i.e., all nodes that have no successors, as SupplyChainNode objects. Read only.

property edges

List of all edges, as tuples whose elements are the indices of the nodes in the edge. Read only.

has_directed_cycle()[source]

Check whether network contains a directed cycle.

Returns

True if network contains a directed cycle, False otherwise.

Return type

bool

initialize()[source]

Initialize the parameters in the object to their default values.

deep_equal_to(other, rel_tol=1e-08)[source]

Check whether network “deeply equals” other, i.e., if all attributes are equal, including attributes that are themselves objects.

Parameters
  • other (SupplyChainNetwork) – The network to compare this one to.

  • rel_tol (float, optional) – Relative tolerance to use when comparing equality of float attributes.

Returns

True if the two networks are equal, False otherwise.

Return type

bool

to_dict()[source]

Convert the SupplyChainNetwork object to a dict. Converts the object recursively, calling to_dict() on each SupplyChainNode in the network.

Returns

The dict representation of the network.

Return type

dict

classmethod from_dict(the_dict)[source]

Return a new SupplyChainNetwork object with attributes copied from the values in the_dict.

Parameters

the_dict (dict) – Dict representation of a SupplyChainNetwork, typically created using to_dict().

Returns

The object converted from the dict.

Return type

SupplyChainNetwork

get_node_from_index(index)[source]

Return SupplyChainNode object with the specified index, or None if no matching node is found.

Deprecated since version 1.1: Use node_from_index instead.

Parameters

index (int) – Index of node to find.

Returns

The node whose index is index, or None if none.

Return type

SupplyChainNode

reindex_nodes(old_to_new_dict, new_names=None)[source]

Change indices of the nodes in the network using old_to_new_dict. If new_names is provided, also updates name attribute of the nodes.

Parameters
  • old_to_new_dict (dict) – Dict in which keys are old indices and values are new indices.

  • new_names (dict, optional) – Dict in which keys are old indices and values are new names.

add_node(node)[source]

Add node to the network. node will not be connected to other nodes that might be in the network already unless it has already been set as a predecessor or successor to another node in the network.

If node is already in the network (as determined by the index), do nothing.

Parameters

node (SupplyChainNode) – The node to add to the network.

add_edge(from_index, to_index)[source]

Add an edge to the network to and from the nodes with the specified indices. If the edge is already in the network, does nothing.

Parameters
  • from_index (int) – Index of “from” node.

  • to_index (int) – Index of “to” node.

Raises

ValueError – If either index is not in the network.

add_edges_from_list(edge_list)[source]

Add multiple edges to the network from a list of index tuples. Any edge that is already in the network is ignored.

Parameters

edge_list (list) – List of tuples of indices of nodes in edges.

Raises

ValueError – If any of the nodes are not in the network.

add_successor(node, successor_node)[source]

Add successor_node as a successor to node. node must already be contained in the network.

The method adds the nodes to each other’s lists of successors and predecessors. If successor_node is not already contained in the network, the method also adds it. (The node is assumed to be contained in the network if its index or name match those of a node in the network.)

Parameters
  • node (SupplyChainNode) – The node to which the successor should be added.

  • successor_node (SupplyChainNode) – The node to be added as a successor.

add_predecessor(node, predecessor_node)[source]

Add predecessor_node as a predecessor to node. node must already be contained in the network.

The method adds the nodes to each other’s lists of successors and predecessors. If predecessor_node is not already contained in the network, the method also adds it. (The node is assumed to be contained in the network if its index or name match those of a node in the network.)

Parameters
  • node (SupplyChainNode) – The node to which the successor should be added.

  • predecessor_node (SupplyChainNode) – The node to be added as a predecessor.

remove_node(node)[source]

Remove a node from the network. Remove the node from the node list and from its predecessors’ and successors’ successors and predecessors lists.

If node is not in the network (as determined by the index), do nothing.

Parameters

node (SupplyChainNode) – The node to remove.

networkx_digraph()[source]

Build a NetworkX DiGraph object with the same structure as the SupplyChainNetwork.

Returns

digraph – The networkx digraph object.

Return type

DiGraph

add_product(product)[source]

Add product to the network. product will not automatically be contained in any nodes that might be in the network already. If product is already in the network (as determined by the index), do nothing.

It is not necessary to add products using this function if they are handled by nodes in the network. The only reason to use this function is to add a product to a network that is not handled by any node in the network, which is not typical, or when loading a network from a file..

Parameters

product (SupplyChainProduct) – The product to add locally to the network.

remove_product(product)[source]

Remove a product from the network. If product is not in the network (as determined by the index), do nothing. product may be either a SupplyChainProduct object or the index of the product.

The product is removed locally from the network itself but is not removed from any nodes within the network. If the product is handled by any of those nodes, it will still be included in self.products.

Parameters

product (SupplyChainProduct or int) – The product to remove locally from the network.

parse_node(node, allow_none=True)[source]

Return the node and node index as a tuple, whether node is a SupplyChainNode object or an int.

Parameters
  • node (SupplyChainNode or int) – The node itself (as a SupplyChainNode) or its index (as an int).

  • allow_none (bool, optional) – If True (the default), node may be None, in which case the function returns None, None. If False, raises an exception.

Returns

  • |class_node| – The node object.

  • int – The node index.

Raises
  • TypeError – If node is not a SupplyChainNode or an int.

  • ValueError – if node is not a node in the network.

parse_product(product, allow_none=True)[source]

Return the product and product index as a tuple, whether product is a SupplyChainProduct object or an int.

Parameters
  • product (SupplyChainProduct or int) – The product itself (as a SupplyChainProduct) or its index (as an int).

  • allow_none (bool, optional) – If True (the default), product may be None, in which case the function returns None, None. If False, raises an exception.

Returns

  • |class_product| – The product object.

  • int – The product index.

Raises
  • TypeError – If product is not a SupplyChainProduct or an int.

  • ValueError – if product is not a product in the network.

network_from_edges(edges, node_order_in_lists=None, **kwargs)[source]

Construct a supply chain network with the specified edges.

The kwargs parameters specify the attributes (data) for the nodes in the network. If they are provided, they must be either a dict, a list, or a singleton, with the following requirements:

  • If the parameter is a dict, then the keys must contain the node indices and the values must contain the corresponding attribute values. If a given node index is contained in the list of edges but is not a key in the dict, the attribute value is set to None for that node.

  • If the parameter is a singleton, then the attribute is set to that value for all nodes.

  • If the parameter is a list and node_order_in_lists is provided, node_order_in_lists must contain the same indices as the nodes in the edges in edges (otherwise a ValueError is raised). The values in the list are assumed to correspond to the node indices in the order they are specified in node_order_in_lists. That is, the value in slot k in the parameter list is assigned to the node with index node_order_in_lists[k]. If a given node index is contained in the list of edges but is not in node_order_in_lists, the attribute value is set to None for that node.

  • If the parameter is a list and node_order_in_lists is not provided, the values in the list are assumed to correspond to the sorted list of node indices in the edge list. That is, the value in slot k in the parameter list is assigned to the node in slot k when the nodes in the edge list are sorted.

If edges is None or [], a single-node network is returned. The index of the node is set to 0, unless node_order_in_lists is provided, in which case the node’s index is set to node_order_in_lists[0]. The rules for kwargs above also apply to the single-node case.

The supply_type attribute is set to ‘U’ at all nodes that have no predecessors and to

None at all other nodes, no matter how (or whether) the corresponding parameter is set.

For the demand_source attribute, you may pass a DemandSource object or the individual attributes of the demand source (mean, round_to_int, etc.). In the latter case, a DemandSource object will be constructed with the specified attributes and filled into the demand_source attribute of the node. Note: If providing individual demand source attributes, the type attribute must be called demand_type to avoid ambiguity with other objects.

Similarly, you may pass Policy and DisruptionProcess objects for the inventory_policy and disruption_process attributes, or you may pass the individual attributes for these objects. Note: If providing individual inventory policy attributes, the type attribute must be called policy_type to avoid ambiguity with other objects.

If kwargs contains a parameter that is not an attribute of SupplyChainNode or one of its attribute objects (DemandSource, Policy, or DisruptionProcess), an AttributeError is raised. (Exception: demand_type and policy_type are allowed even though they are not attributes of SupplyChainNode; see above.)

Note

This function does not check that valid attributes have been provided for demand_source, inventory_policy, and disruption_process. For example, it does not check that a base_stock_level has been provided if the policy type is set to BS.

Parameters
  • edges (list) – List of edges, with each edge specified as a tuple (a, b), where a is the index of the predecessor and b is the index of the successor node. If None or empty, a single-node network is created.

  • node_order_in_lists (list, optional) – 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 the k th node.)

  • kwargs (optional) – Optional keyword arguments to specify node attributes.

Raises

AttributeError – If kwargs contains a parameter that is not an attribute of SupplyChainNode.

single_stage_system(index=0, **kwargs)[source]

Generate a single-stage network.

The kwargs parameters specify the attributes (data) for the node.

For the demand_source attribute, you may pass a DemandSource object or the individual attributes of the demand source (mean, round_to_int, etc.). In the latter case, a DemandSource object will be constructed with the specified attributes and filled into the demand_source attribute of the node. Note: If providing individual demand source attributes, the type attribute must be called demand_type to avoid ambiguity with other objects.

Similarly, you may pass Policy and DisruptionProcess objects for the inventory_policy and disruption_process attributes, or you may pass the individual attributes for these objects. Note: If providing individual inventory policy attributes, the type attribute must be called policy_type to avoid ambiguity with other objects.

If kwargs contains a parameter that is not an attribute of SupplyChainNode or one of its attribute objects (DemandSource, Policy, or DisruptionProcess), an AttributeError is raised. (Exception: demand_type and policy_type are allowed even though they are not attributes of SupplyChainNode; see above.)

Note

This function does not check that valid attributes have been provided for demand_source, inventory_policy, and disruption_process. For example, it does not check that a base_stock_level has been provided if the policy type is set to BS.

Parameters
  • index (int, optional) – Index to use for the node. Default = 0.

  • kwargs (optional) – Optional keyword arguments to specify node attributes.

Returns

network – The single-stage network, with parameters filled.

Return type

SupplyChainNetwork

Raises

AttributeError – If kwargs contains a parameter that is not an attribute of SupplyChainNode.

Example (a SupplyChainNetwork object containing the data from Example 4.1):

>>> network = single_stage_system(holding_cost=0.18,
... stockout_cost=0.70,
... demand_type='N',
... mean=50, standard_deviation=8,
... policy_type='BS',
... base_stock_level=56.6)
>>> network.nodes[0].stockout_cost
0.7
serial_system(num_nodes, node_order_in_system=None, node_order_in_lists=None, **kwargs)[source]

Generate a serial system with the specified number of nodes. By default, node 0 is upstream and node num_nodes - 1 is downstream, but this can be changed by setting node_order_in_system.

The kwargs parameters specify the attributes (data) for the nodes in the network. If they are provided, they must be either a dict, a list, or a singleton, with the following requirements:

  • If the parameter is a dict, then the keys must contain the node indices and the values must contain the corresponding attribute values. If a given node index is contained in node_order_in_system (or in range(num_nodes), if node_order_in_system is not provided) but is not a key in the dict, the attribute value is set to None for that node.

  • If the parameter is a singleton, then the attribute is set to that value for all nodes.

  • If the parameter is a list and node_order_in_lists is provided, node_order_in_lists must contain the same indices as node_order_in_system (if it is provided) or 0, …, num_nodes - 1 (if it is not), otherwise a ValueError is raised. The values in the list are assumed to correspond to the node indices in the order they are specified in node_order_in_lists. That is, the value in slot k in the parameter list is assigned to the node with index node_order_in_lists[k].

  • If the parameter is a list and node_order_in_lists is not provided, the values in the list are assumed to correspond to nodes in the same order as node_order_in_system (or in range(num_nodes), if node_order_in_system is not provided).

demand_source and stockout_cost attributes are only set at the downstream-most node, no matter how (or whether) the corresponding parameter is set. supply_type attribute is set to ‘U’ at the upstream-most node and to None at all other nodes, no matter how (or whether) the corresponding parameter is set.

For the demand_source attribute, you may pass a DemandSource object or the individual attributes of the demand source (mean, round_to_int, etc.). In the latter case, a DemandSource object will be constructed with the specified attributes and filled into the demand_source attribute of the node. Note: If providing individual demand source attributes, the type attribute must be called demand_type to avoid ambiguity with other objects.

Similarly, you may pass Policy and DisruptionProcess objects for the inventory_policy and disruption_process attributes, or you may pass the individual attributes for these objects. Note: If providing individual inventory policy attributes, the type attribute must be called policy_type to avoid ambiguity with other objects.

If kwargs contains a parameter that is not an attribute of SupplyChainNode or one of its attribute objects (DemandSource, Policy, or DisruptionProcess), an AttributeError is raised. (Exception: demand_type and policy_type are allowed even though they are not attributes of SupplyChainNode; see above.)

Note

This function does not check that valid attributes have been provided for demand_source, inventory_policy, and disruption_process. For example, it does not check that a base_stock_level has been provided if the policy type is set to BS.

Parameters
  • num_nodes (int) – Number of nodes in the serial system.

  • node_order_in_system (list, optional) – List of node indices in the order that they appear in the serial system, with upstream-most node listed first. If omitted, the system will be indexed 0, …, num_nodes - 1.

  • node_order_in_lists (list, optional) – 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 the k th node.)

  • kwargs (optional) – Optional keyword arguments to specify node attributes.

Raises

AttributeError – If kwargs contains a parameter that is not an attribute of SupplyChainNode.

Example (a SupplyChainNetwork object containing the data from Example 4.1):

>>> network = single_stage_system(holding_cost=0.18,
... stockout_cost=0.70,
... demand_type='N',
... mean=50, standard_deviation=8,
... policy_type='BS',
... base_stock_level=56.6)
>>> network.nodes[0].stockout_cost
0.7
owmr_system(num_retailers, node_order_in_system=None, node_order_in_lists=None, **kwargs)[source]

Generate a one-warehouse, multiple-retailer (OWMR) (i.e., 2-echelon distribution) system with the specified number of retailers. By default, node 0 is the warehouse and nodes 1, …, num_retailers are the retailers, but this can be changed by setting node_order_in_system.

The kwargs parameters specify the attributes (data) for the nodes in the network. If they are provided, they must be either a dict, a list, or a singleton, with the following requirements:

  • If the parameter is a dict, then the keys must contain the node indices and the values must contain the corresponding attribute values. If a given node index is contained in node_order_in_system (or in range(num_nodes), if node_order_in_system is not provided) but is not a key in the dict, the attribute value is set to None for that node.

  • If the parameter is a singleton, then the attribute is set to that value for all nodes.

  • If the parameter is a list and node_order_in_lists is provided, node_order_in_lists must contain the same indices as the nodes in the edges in edges (otherwise a ValueError is raised). The values in the list are assumed to correspond to the node indices in the order they are specified in node_order_in_lists. That is, the value in slot k in the parameter list is assigned to the node with index node_order_in_lists[k]. If a given node index is contained in the list of edges but is not in node_order_in_lists, the attribute value is set to None for that node.

  • If the parameter is a list and node_order_in_lists is not provided, the values in the list are assumed to correspond to nodes in the same order as node_order_in_system (or in range(num_retailers+1), if node_order_in_system is not provided).

demand_source attribute is not set at the warehouse node, no matter how (or whether) the corresponding parameter is set.``supply_type`` attribute is set to ‘U’ at the warehouse node and to None at all other nodes, no matter how (or whether) the corresponding parameter is set.

For the demand_source attribute, you may pass a DemandSource object or the individual attributes of the demand source (mean, round_to_int, etc.). In the latter case, a DemandSource object will be constructed with the specified attributes and filled into the demand_source attribute of the node. Note: If providing individual demand source attributes, the type attribute must be called demand_type to avoid ambiguity with other objects.

Similarly, you may pass Policy and DisruptionProcess objects for the inventory_policy and disruption_process attributes, or you may pass the individual attributes for these objects. Note: If providing individual inventory policy attributes, the type attribute must be called policy_type to avoid ambiguity with other objects.

If kwargs contains a parameter that is not an attribute of SupplyChainNode or one of its attribute objects (DemandSource, Policy, or DisruptionProcess), an AttributeError is raised. (Exception: demand_type and policy_type are allowed even though they are not attributes of SupplyChainNode; see above.)

Note

This function does not check that valid attributes have been provided for demand_source, inventory_policy, and disruption_process. For example, it does not check that a base_stock_level has been provided if the policy type is set to BS.

Parameters
  • num_retailers (int) – Number of retailers in OWMR system.

  • node_order_in_system (list, optional) – List of node indices in the order that they appear in the OWMR system, with warehouse node first and retailer nodes last. If omitted, the warehouse will have index 0 and the retailers will have indices 1, …, num_retailers.

  • node_order_in_lists (list, optional) – 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 the k th node.)

  • kwargs (optional) – Optional keyword arguments to specify node attributes.

Raises

AttributeError – If kwargs contains a parameter that is not an attribute of SupplyChainNode.

mwor_system(num_warehouses, node_order_in_system=None, node_order_in_lists=None, **kwargs)[source]

Generate a multiple-warehouse, one-retailer (MWOR) (i.e., 2-echelon assembly) system with the specified number of warehouses. By default, node 0 is the retailer and nodes 1, …, num_warehouses are the warehouses, but this can be changed by setting node_order_in_system.

The kwargs parameters specify the attributes (data) for the nodes in the network. If they are provided, they must be either a dict, a list, or a singleton, with the following requirements:

  • If the parameter is a dict, then the keys must contain the node indices and the values must contain the corresponding attribute values. If a given node index is contained in node_order_in_system (or in range(num_nodes), if node_order_in_system is not provided) but is not a key in the dict, the attribute value is set to None for that node.

  • If the parameter is a singleton, then the attribute is set to that value for all nodes.

  • If the parameter is a list and node_order_in_lists is provided, node_order_in_lists must contain the same indices as the nodes in the edges in edges (otherwise a ValueError is raised). The values in the list are assumed to correspond to the node indices in the order they are specified in node_order_in_lists. That is, the value in slot k in the parameter list is assigned to the node with index node_order_in_lists[k]. If a given node index is contained in the list of edges but is not in node_order_in_lists, the attribute value is set to None for that node.

  • If the parameter is a list and node_order_in_lists is not provided, the values in the list are assumed to correspond to nodes in the same order as node_order_in_system (or in range(num_warehouses+1), if node_order_in_system is not provided).

demand_source attribute is only set at the retailer node, no matter how (or whether) the corresponding parameter is set. supply_type attribute is set to ‘U’ at the warehouse nodes and to None at the retailer node, no matter how (or whether) the corresponding parameter is set.

For the demand_source attribute, you may pass a DemandSource object or the individual attributes of the demand source (mean, round_to_int, etc.). In the latter case, a DemandSource object will be constructed with the specified attributes and filled into the demand_source attribute of the node. Note: If providing individual demand source attributes, the type attribute must be called demand_type to avoid ambiguity with other objects.

Similarly, you may pass Policy and DisruptionProcess objects for the inventory_policy and disruption_process attributes, or you may pass the individual attributes for these objects. Note: If providing individual inventory policy attributes, the type attribute must be called policy_type to avoid ambiguity with other objects.

If kwargs contains a parameter that is not an attribute of SupplyChainNode or one of its attribute objects (DemandSource, Policy, or DisruptionProcess), an AttributeError is raised. (Exception: demand_type and policy_type are allowed even though they are not attributes of SupplyChainNode; see above.)

Note

This function does not check that valid attributes have been provided for demand_source, inventory_policy, and disruption_process. For example, it does not check that a base_stock_level has been provided if the policy type is set to BS.

Parameters
  • num_warehouses (int) – Number of warehouses in MWOR system.

  • node_order_in_system (list, optional) – List of node indices in the order that they appear in the MWOR system, with warehouse nodes first and retailer node last. If omitted, the retailer will have index 0 and the warehouses will have indices 1, …, num_warehouses.

  • node_order_in_lists (list, optional) – 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 the k th node.)

  • kwargs (optional) – Optional keyword arguments to specify node attributes.

Raises

AttributeError – If kwargs contains a parameter that is not an attribute of SupplyChainNode.

local_to_echelon_base_stock_levels(network, S_local)[source]

Convert local base-stock levels to echelon base-stock levels for a serial system.

Assumes network is serial system but does not assume anything about the labeling of the nodes.

Parameters
  • network (SupplyChainNetwork) – The serial inventory network.

  • S_local (dict) – Dict of local base-stock levels.

Returns

S_echelon – Dict of echelon base-stock levels.

Return type

dict

echelon_to_local_base_stock_levels(network, S_echelon)[source]

Convert echelon base-stock levels to local base-stock levels for a serial system.

Assumes network is serial system but does not assume anything about the labeling of the nodes.

Parameters
  • network (SupplyChainNetwork) – The serial inventory network.

  • S_echelon (dict) – Dict of echelon base-stock levels.

Returns

S_local – Dict of local base-stock levels.

Return type

dict