supply_chain_node Module

Overview

This module contains the SupplyChainNode class, which is a stage or node in a supply chain network.

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 SupplyChainNode is used primarily for multi-echelon inventory optimization (MEIO) or simulation. SupplyChainNode objects are rarely, if ever, used as standalone objects; rather, they are included in SupplyChainNetwork objects, which describe the complete instance to be optimized or simulated.

The node object contains many attributes, and different functions use different sets of attributes. For example, the stockpyl.ssm_serial.optimize_base_stock_levels() function takes a SupplyChainNetwork whose nodes contain values for echelon_holding_cost, lead_time, stockout_cost, and demand_source attributes, while stockpyl.gsm_serial.optimize_committed_service_times() uses local_holding_cost, processing_time, etc. Therefore, to determine which attributes are needed, refer to the documentation for the function you are using.

API Reference

class SupplyChainNode(index, name=None, network=None, **kwargs)[source]

The SupplyChainNode class contains the data, state variables, and performance measures for a supply chain node.

network

The network that contains the node.

Type

SupplyChainNetwork

local_holding_cost

Local holding cost, per unit per period. [\(h'\)]

Type

float

echelon_holding_cost

Echelon holding cost, per unit per period. (Note: not currently supported.) [\(h\)]

Type

float

local_holding_cost_function

Function that calculates local holding cost per period, as a function of ending inventory level. Function must take exactly one argument, the ending IL. Function should check that IL > 0.

Type

function

in_transit_holding_cost

Holding cost coefficient used to calculate in-transit holding cost for shipments en route from the node to its downstream successors, if any. If in_transit_holding_cost is None, then the stage’s local_holding_cost is used. To ignore in-transit holding costs, set in_transit_holding_cost = 0.

Type

float

stockout_cost

Stockout cost, per unit (per period, if backorders). [\(p\)]

Type

float

stockout_cost_function

Function that calculates stockout cost per period, as a function of ending inventory level. Function must take exactly one argument, the ending IL. Function should check that IL < 0.

Type

function

purchase_cost

Cost incurred per unit. (Note: not currently supported.)

Type

float

revenue

Revenue earned per unit of demand met. (Note: not currently supported.) [\(r\)]

Type

float

shipment_lead_time

Shipment lead time. [\(L\)]

Type

int

lead_time

An alias for shipment_lead_time.

Type

int

order_lead_time

Order lead time. (Note: not currently supported.)

Type

int

demand_source

Demand source object.

Type

DemandSource

initial_inventory_level

Initial inventory level.

Type

float

initial_orders

Initial outbound order quantity.

Type

float

initial shipments

Initial inbound shipment quantity.

Type

float

inventory_policy

Inventory policy to be used to make inventory decisions.

Type

Policy

supply_type

Supply type , as a string. Currently supported strings are:

  • None

  • ‘U’: unlimited

Type

str

order_capacity

Maximum size of an order.

Type

float

disruption_process

Disruption process object (if any).

Type

DisruptionProcess

state_vars

List of NodeStateVars, one for each period in a simulation.

Type

list of NodeStateVars

problem_specific_data

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

Type

object

predecessors(include_external=False)[source]

Return a list of all predecessors of the node, as SupplyChainNode objects.

Parameters

include_external (bool, optional) – Include the external supplier (if any)? Default = False.

Returns

List of all predecessors, as SupplyChainNode objects.

Return type

list

successors(include_external=False)[source]

Return a list of all successors of the node, as SupplyChainNode objects.

Parameters

include_external (bool, optional) – Include the external customer (if any)? Default = False.

Returns

List of all successors, as SupplyChainNode objects.

Return type

list

predecessor_indices(include_external=False)[source]

Return a list of indices of all predecessors of the node.

Parameters

include_external (bool, optional) – Include the external supplier (if any)? Default = False.

Returns

List of all predecessor indices.

Return type

list

successor_indices(include_external=False)[source]

Return a list of indices of all successors of the node.

Parameters

include_external (bool, optional) – Include the external customer (if any)? Default = False.

Returns

List of all successor indices.

Return type

list

property descendants

A list of all descendants of the node, as SupplyChainNode objects. A descendant is a node that is downstream from the node but not necessarily directly adjacent; that is, a node that can be reached from the node via a directed path. Read only.

property ancestors

A list of all ancestors of the node, as SupplyChainNode objects. An ancestor is a node that is upstream from the node but not necessarily directly adjacent; that is, a node from which we can reach the node via a directed path. Read only.

property neighbors

A list of all neighbors (successors and predecessors) of the node, as SupplyChainNode objects. Read only.

property neighbor_indices

A list of indices of all neighbors (successors and predecessors) of the node. Read only.

property holding_cost

An alias for local_holding_cost. Read only.

property forward_echelon_lead_time

Total shipment lead time for node and all of its descendants. Rosling (1989) calls this \(M_i\); Zipkin (2000) calls it \(\underline{L}_j\). Some assembly-system algorithms assume that the nodes are indexed in order of forward echelon lead time. Read only.

property equivalent_lead_time

Difference between forward echelon lead time for the node (node \(i\)) and for node \(i-1\), where the nodes are indexed in non-decreasing order of forward_echelon_lead_time, consecutively. (If nodes are not indexed in this way, results will be unreliable.)

If node is the smallest-indexed node in the network, equivalent lead time equals forward echelon lead time, which also equals shipment lead time.

Rosling (1989) calls this \(L_i\); Zipkin (2000) calls it \(L''_j\).

Read only.

property derived_demand_mean

Mean of derived demand, i.e., external demand at node and all of its descendants. Read only.

property derived_demand_standard_deviation

Standard deviation of derived demand, i.e., external demand at node and all of its descendants. Read only.

property state_vars_current

An alias for the most recent set of state variables, i.e., for the current period. (Period is determined from self.network.period). Read only.

property disrupted

Is the node currently disrupted?

(Works even if the node has no DisruptionProcess object in its disruption_process attribute.)

initialize()[source]

Initialize the parameters in the object to their default values. Also initializes attributes that are objects (demand_source, disruption_process, _inventory_policy):

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

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

Note the following caveats:

  • Does not check equality of network.

  • Checks predecessor and successor equality by index only.

  • Does not check equality of local_holding_cost_function or stockout_cost_function.

  • Does not check equality of state_vars.

Parameters
  • other (SupplyChainNode) – The node to compare this one to.

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

Returns

True if the two nodes are equal, False otherwise.

Return type

bool

to_dict()[source]

Convert the SupplyChainNode object to a dict. Converts the object recursively, calling to_dict() on each object that is an attribute of the node (DemandSource, etc.).

Successors and predecessors are stored as their indices only, not SupplyChainNode objects. They should be replaced with the node objects if this function is called recursively from a SupplyChainNetwork’s from_dict() method.

Similarly, network object is not filled, but should be filled with the network object if this function is called recursively from a SupplyChainNetwork’s from_dict() method.

Returns

The dict representation of the node.

Return type

dict

classmethod from_dict(the_dict)[source]

Return a new SupplyChainNode object with attributes copied from the values in the_dict. List attributes are deep-copied so changes to the original dict do not get propagated to the object.

_predecessors and _successors attributes are set to the indices of the nodes, like they are in the dict, but should be converted to node objects if this function is called recursively from a SupplyChainNetwork’s from_dict() method.

Similarly, network object is not filled, but should be filled with the network object if this function is called recursively from a SupplyChainNetwork’s from_dict() method.

Parameters

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

Returns

The object converted from the dict.

Return type

SupplyChainNode

add_successor(successor)[source]

Add successor to the node’s list of successors.

Important

This method simply updates the node’s list of successors. It does not add successor to the network or add self as a predecessor of successor. Typically, this method is called by the network rather than directly. Use the add_successor() method in SupplyChainNetwork instead.

Parameters

successor (SupplyChainNode) – The node to add as a successor.

add_predecessor(predecessor)[source]

Add predecessor to the node’s list of predecessors.

Important

This method simply updates the node’s list of predecessors. It does not add predecessor to the network or add self as a successor of predecessor. Typically, this method is called by the network rather than directly. Use the add_predecessor() method in SupplyChainNetwork instead.

Parameters

predecessor (SupplyChainNode) – The node to add as a predecessor.

remove_successor(successor)[source]

Remove successor from the node’s list of successors.

Important

This method simply updates the node’s list of successors. It does not remove successor from the network or remove self as a predecessor of successor. Typically, this method is called by the remove_node() method of the SupplyChainNetwork rather than directly.

Parameters

successor (SupplyChainNode) – The node to remove as a successor.

remove_predecessor(predecessor)[source]

Remove predecessor from the node’s list of predecessors.

Important

This method simply updates the node’s list of predecessors. It does not remove predecessor from the network or remove self as a successor of predecessor. Typically, this method is called by the remove_node() method of the SupplyChainNetwork rather than directly.

Parameters

predecessor (SupplyChainNode) – The node to remove as a predecessor.

get_one_successor()[source]

Get one successor of the node. If the node has more than one successor, return the first in the list. If the node has no successors, return None.

Returns

successor – A successor of the node.

Return type

SupplyChainNode

get_one_predecessor()[source]

Get one predecessor of the node. If the node has more than one predecessor, return the first in the list. If the node has no predecessor, return None.

Returns

predecessor – A predecessor of the node.

Return type

SupplyChainNode

reindex_all_state_variables(old_to_new_dict)[source]

Change indices of all keys in all state variables using old_to_new_dict.

Parameters

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

class NodeStateVars(node=None, period=None)[source]

The NodeStateVars class contains values of the state variables for a supply chain node during a simulation. All state variables refer to their values at the end of a period (except during the period itself, in which case the values might be intermediate until the period is complete).

node

The node the state variables refer to.

Type

SupplyChainNode

period

The period of the simulation that the state variables refer to.

Type

int

inbound_shipment_pipeline

inbound_shipment_pipeline[p][r] = shipment quantity arriving from predecessor node p in r periods from the current period. If p is None, refers to external supply.

Type

dict

inbound_shipment

inbound_shipment[p] = shipment quantity arriving at node from predecessor node p in the current period. If p is None, refers to external supply.

Type

dict

inbound_order_pipeline

inbound_order_pipeline[s][r] = order quantity arriving from successor node s in r periods from the current period. If s is None, refers to external demand.

Type

dict

inbound_order

inbound_order[s] = order quantity arriving at node from successor node s in the current period. If s is None, refers to external demand.

Type

dict

demand_cumul

Cumulative demand (from all sources, internal and external) from period 0 through the current period. (Used for fill_rate calculation.)

Type

float

outbound_shipment

outbound_shipment[s] = outbound shipment to successor node s. If s is None, refers to external demand.

Type

dict

on_order_by_predecessor

on_order_by_predecessor[p] = on-order quantity (items that have been ordered from successor node p but not yet received) at node. If p is None, refers to external supply.

Type

dict

inventory_level

Inventory level (positive, negative, or zero) at node

Type

float

backorders_by_successor

backorders_by_successor[s] = number of backorders for successor s. If s is None, refers to external demand.

Type

dict

outbound_disrupted_items

outbound_disrupted_items[s] = number of items held for successor s due to a type-SP disruption at s. (Since external demand cannot be disrupted, outbound_disrupted_items[None] always = 0.) Items held for successor are not included in backorders_by_successor. Sum over all successors of backorders_by_successor + outbound_disrupted_items should always equal max{0, -inventory_level}.

Type

dict

inbound_disrupted_items

inbound_disrupted_items[p] = number of items from predecessor p that are being held before receipt due to a type-RP disruption at the node.

Type

dict

raw_material_inventory

raw_material_inventory[p] = number of units of predecessor p’s product in raw-material inventory at node. If p is None, refers to external supply.

Type

dict

disrupted

True if the node was disrupted in the period, False otherwise.

Type

bool

holding_cost_incurred

Holding cost incurred at the node in the period.

Type

float

stockout_cost_incurred

Stockout cost incurred at the node in the period.

Type

float

in_transit_holding_cost_incurred

In-transit holding cost incurred at the node in the period.

Type

float

revenue_earned

Revenue earned at the node in the period.

Type

float

total_cost_incurred

Total cost (less revenue) incurred at the node in the period.

Type

float

demand_met_from_stock

Demands met from stock at the node in the period.

Type

float

demand_met_from_stock_cumul

Cumulative demands met from stock from period 0 through the current period. (Used for fill_rate calculation.)

Type

float

fill_rate

Cumulative fill rate in periods 0, …, period.

Type

float

order_quantity

order_quantity[p] = order quantity placed by the node to predecessor p in period. If p is None, refers to external supply.

Type

dict

property on_hand

Current on-hand inventory. Read only.

property backorders

Current number of backorders. Should always equal sum over all successors s of backorders_by_successor[s] + outbound_disrupted_items[s]. Read only.

in_transit_to(successor)[source]

Return current total inventory in transit to a given successor. (Declared as a function, not a property, because needs to take an argument.) Includes items that will be/have been delivered during the current period.

Parameters

successor (SupplyChainNode) – The successor node.

Return type

The current inventory in transit to the successor.

in_transit_from(predecessor)[source]

Return current total inventory in transit from a given predecessor. (Declared as a function, not a property, because needs to take an argument.) Includes items that will be/have been delivered during the current period (self.network.period).

Parameters

predecessor (SupplyChainNode) – The predecessor node (or None for external supplier).

Return type

The current inventory in transit from the predecessor.

property in_transit

Current total inventory in transit to the node. If node has more than 1 predecessor (it is an assembly node), including external supplier, in-transit items are counted using the “units” of the node itself. That is, they are divided by the total number of predecessors. Read only.

property on_order

Current total on-order quantity. If node has more than 1 predecessor (it is an assembly node), including external supplier, on-order items are counted using the “units” of the node itself. That is, they are divided by the total number of predecessors. Read only.

property raw_material_aggregate

Total raw materials at the node. Raw materials are counted using the “units” of the node itself. That is, they are divided by the total number of predecessors. Read only.

property inbound_disrupted_items_aggregate

Total inbound disrupted items at the node. Inbound disrupted items are counted using the “units” of the node itself. That is, they are divided by the total number of predecessors. Read only.

inventory_position(predecessor_index=None)[source]

Current local inventory position at node. Equals inventory level plus on-order inventory. On-order includes raw material inventory that has not yet been processed, as well as inbound disrupted items due to type-RP disruptions. If the node has more than one predecessor (including external supplier), set predecessor_index for predecessor-specific inventory position, or set to None to use aggregate on-order and raw material inventory (counting such items using the “units” of the node itself).

Parameters

predecessor_index (int, optional) – Predecessor to consider in inventory position calculation (excluding all others), or None to include all predecessors.

Returns

The inventory position.

Return type

float

property echelon_on_hand_inventory

Current echelon on-hand inventory at node. Equals on-hand inventory at node and at or in transit to all of its downstream nodes. Read only.

property echelon_inventory_level

Current echelon inventory level at node. Equals echelon on-hand inventory minus backorders at terminal node(s) downstream from node. Read only.

echelon_inventory_position(predecessor_index=None)[source]

Current echelon inventory position at node. Equals echelon inventory level plus on order items. On-order includes raw material inventory that has not yet been processed. If the node has more than one predecessor (including external supplier), set predecessor_index for predecessor-specific inventory position, or set to None to use aggregate on-order and raw material inventory (counting such items using the “units” of the node itself).

Parameters

predecessor_index (int, optional) – Predecessor to consider in inventory position calculation (excluding all others), or None to include all predecessors.

Returns

The echelon inventory position.

Return type

float

to_dict()[source]

Convert the NodeStateVars object to a dict. List and dict attributes are deep-copied so changes to the original object do not get propagated to the dict.

The node attribute is set to the index of the node (if any), rather than to the object.

Returns

The dict representation of the object.

Return type

dict

classmethod from_dict(the_dict)[source]

Return a new NodeStateVars object with attributes copied from the values in the_dict. List and dict attributes are deep-copied so changes to the original dict do not get propagated to the object.

The node attribute is set to the index of the node, like it is in the dict, but should be converted to a node object if this function is called recursively from a SupplyChainNode’s from_dict() method.

Parameters

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

Returns

The object converted from the dict.

Return type

NodeStateVars

reindex_state_variables(old_to_new_dict)[source]

Change indices of state variable dict keys using old_to_new_dict.

Parameters

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

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

Check whether object “deeply equals” other, i.e., if all attributes are equal, including attributes that are lists or dicts.

Note the following caveats:

  • Checks the equality of node.index but not the entire node object.

Parameters
  • other (NodeStateVars) – The state variables to compare this one to.

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

Returns

True if the two state variables objects are equal, False otherwise.

Return type

bool