discrete_optimization.lotsizing package

Subpackages

Submodules

discrete_optimization.lotsizing.backlog module

Backlog feature mixin for lot sizing problems.

This module provides mixins for problems that allow backlogged demand (demand satisfied in later periods).

class discrete_optimization.lotsizing.backlog.BacklogProblem[source]

Bases: DemandsProblem[Item], Generic[Item]

Mixin for problems allowing backlogged demand.

Backlog B_it represents the cumulative demand not yet satisfied at end of period t. A cost b_it is incurred per unit of backlog.

When backlog is allowed, the demand satisfaction constraint is relaxed: instead of requiring delivery in period t, demand can be satisfied in later periods.

abstractmethod get_backlog_cost_per_unit(item: Item, period: int) float[source]

Get cost per unit of backlogged demand.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Backlog cost b_it per unit (non-negative)

abstractmethod is_backlog_allowed() bool[source]

Check whether backlog is allowed in this problem.

Returns:

True if backlog is permitted, False if demands must be satisfied on time

class discrete_optimization.lotsizing.backlog.BacklogSolution(problem: Problem)[source]

Bases: DemandsSolution[Item], Generic[Item]

Solution mixin for backlog handling.

check_backlog_constraints() bool[source]

Check backlog constraints.

If backlog is not allowed, verify that no backlog exists (all demands satisfied on time).

Returns:

True if constraints satisfied, False otherwise

compute_total_backlog_cost() float[source]

Compute total backlog cost across all items and periods.

Returns:

Sum of b_it * B_it

abstractmethod get_backlog_quantity(item: Item, period: int) int[source]

Get backlog quantity at end of period.

Backlog is the cumulative demand not yet satisfied:

B_it = max(0, cumulative_demand_it - cumulative_delivery_it)

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Backlog quantity B_it (non-negative integer)

get_max_backlog() int[source]

Get maximum backlog across all items and periods.

Useful for solution quality assessment.

Returns:

max_i,t B_it

get_total_backlog_at_period(period: int) int[source]

Get total backlog across all items at a given period.

Parameters:

period – Time period

Returns:

Sum of backlog for all items at this period

problem: BacklogProblem[Item]
class discrete_optimization.lotsizing.backlog.WithoutBacklogProblem[source]

Bases: BacklogProblem[Item], Generic[Item]

Utility mixin for problems without backlog.

This is the “Without” variant for problems where demands must be satisfied on time. Backlog costs are zero and backlog is not allowed.

get_backlog_cost_per_unit(item: Item, period: int) float[source]

No backlog cost.

is_backlog_allowed() bool[source]

Backlog not allowed.

class discrete_optimization.lotsizing.backlog.WithoutBacklogSolution(problem: Problem)[source]

Bases: BacklogSolution[Item], Generic[Item]

Solution mixin for problems without backlog.

All backlog quantities are zero.

check_backlog_constraints() bool[source]

Always satisfied (no backlog to check).

compute_total_backlog_cost() float[source]

No backlog cost.

get_backlog_quantity(item: Item, period: int) int[source]

No backlog.

get_max_backlog() int[source]

No backlog.

get_total_backlog_at_period(period: int) int[source]

No backlog.

discrete_optimization.lotsizing.base module

Base classes for lot sizing problems.

This module provides minimal base classes following the generic_tasks_tools pattern. Each problem variant is composed of mixins that add specific features.

class discrete_optimization.lotsizing.base.LotSizingProblem[source]

Bases: Problem, Generic[Item]

Minimal base class for all lot sizing problems.

This class only defines the essential structure common to ALL lot sizing variants: - Time horizon (number of periods) - Items/products to produce

All other features (demands, costs, capacity, etc.) are added via mixins.

Similar to TasksProblem in generic_tasks_tools.

get_index_from_item(item: Item) int[source]

Get index of item in items_list.

This is cached for efficiency when items_list doesn’t change.

Parameters:

item – Item identifier

Returns:

Index in items_list (0 to nb_items-1)

get_item_from_index(i: int) Item[source]

Get item from index.

Parameters:

i – Index in items_list

Returns:

Item identifier

abstract property horizon: int

Number of time periods T.

Periods are indexed from 0 to horizon-1.

abstract property items_list: list[Item]

List of all items (product types) to schedule production for.

Returns:

List of unique item identifiers

property nb_items: int

Number of different items/products.

update_items_list() None[source]

Call when items_list is updated to reset cache.

class discrete_optimization.lotsizing.base.LotSizingSolution(problem: Problem)[source]

Bases: Solution, Generic[Item]

Minimal base class for lot sizing solutions.

This is the base for all solution types. Specific solution representations are added by mixins and concrete implementations.

Similar to TasksSolution in generic_tasks_tools.

abstractmethod get_delivery_quantity(item: Item, period: int) int[source]

Get quantity of item delivered to satisfy demand in period.

This may differ from production quantity due to inventory.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Delivery quantity (amount used to satisfy demand in this period)

abstractmethod get_inventory_level(item: Item, period: int)[source]

Get inventory level at end of period.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Inventory level I_it (non-negative integer)

abstractmethod get_production_quantity(item: Item, period: int) int[source]

Get production quantity X_it.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Production quantity (non-negative integer)

get_total_delivery_quantity(item: Item) int[source]
get_total_production_quantity(item: Item) int[source]
problem: LotSizingProblem[Item]

discrete_optimization.lotsizing.capacity module

Capacity constraint mixins for lot sizing problems.

This module provides mixins for production capacity constraints, distinguishing between uncapacitated and capacitated variants.

class discrete_optimization.lotsizing.capacity.CapacityProblem[source]

Bases: DemandsProblem[Item], Generic[Item]

Mixin for problems with production capacity constraints.

Capacitated problems have a limit on total production time available in each period. The capacity constraint is typically:

sum_i (p_it * X_it) <= h_t

Where: - p_it: production time per unit of item i in period t - X_it: production quantity - h_t: available production time in period t

abstractmethod get_available_production_time(period: int) float[source]

Get available production time h_t in period t.

Parameters:

period – Time period

Returns:

Available capacity (non-negative, may be infinite for uncapacitated)

get_max_production_quantity(item: Item, period: int) int[source]
abstractmethod get_production_time_per_unit(item: Item, period: int) float[source]

Get production time per unit p_it.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Production time per unit (non-negative)

has_capacity_limits() bool[source]
has_constant_capacity()[source]
class discrete_optimization.lotsizing.capacity.CapacitySolution(problem: Problem)[source]

Bases: DemandsSolution[Item], Generic[Item]

Solution mixin for capacity constraint checking.

check_capacity_constraints() bool[source]

Check if capacity constraints are satisfied in all periods.

Returns:

True if capacity constraints satisfied, False otherwise

get_capacity_utilization(period: int) float[source]

Get capacity utilization ratio for a period.

Parameters:

period – Time period

Returns:

Ratio of used / available capacity (may be > 1 if violated)

get_total_production_time_used(period: int) float[source]

Compute total production time used in period.

This base implementation only considers production quantities. Subclasses (like SetupTimesSolution) may add setup times.

Parameters:

period – Time period

Returns:

Total production time used

problem: CapacityProblem[Item]
class discrete_optimization.lotsizing.capacity.WithoutCapacityProblem[source]

Bases: CapacityProblem[Item], Generic[Item]

Utility mixin for uncapacitated problems.

Returns infinite capacity - no production time constraints.

This is the “Without” variant following the generic_tasks_tools pattern. Use this when the problem is uncapacitated (ULSP - Uncapacitated Lot-Sizing Problem).

get_available_production_time(period: int) float[source]

Infinite capacity available.

get_production_time_per_unit(item: Item, period: int) float[source]

No time per unit constraint in uncapacitated problems.

has_capacity_limits() bool[source]
class discrete_optimization.lotsizing.capacity.WithoutCapacitySolution(problem: Problem)[source]

Bases: CapacitySolution[Item], Generic[Item]

Solution mixin for uncapacitated problems.

Capacity constraints are always satisfied (no constraints).

check_capacity_constraints() bool[source]

Always satisfied for uncapacitated problems.

get_capacity_utilization(period: int) float[source]

Utilization is undefined for uncapacitated problems.

discrete_optimization.lotsizing.changeover module

Sequence-dependent changeover costs mixin for lot sizing problems.

This module provides mixins for problems where the cost of setup depends on the sequence of production (which item was produced previously).

class discrete_optimization.lotsizing.changeover.ChangeoverCostsProblem[source]

Bases: DemandsProblem[Item], Generic[Item]

Mixin for sequence-dependent changeover costs.

Relevant for multi-item problems where the order of production matters. Changeover cost c_ij is the cost to switch from producing item i to item j.

This is different from setup costs which are item-specific and time-dependent. Changeover costs depend on the production sequence.

abstractmethod get_changeover_array() list[source]
get_changeover_cost(from_item: Item, to_item: Item) float[source]

Get sequence-dependent changeover cost.

Cost incurred when switching production from item i to item j.

Parameters:
  • from_item – Item produced previously

  • to_item – Item to be produced next

Returns:

Changeover cost c_ij (non-negative)

get_max_changeover_cost() float[source]
has_changeover_costs() bool[source]

Check if changeover costs are significant.

Returns:

True if any changeover cost is non-zero

class discrete_optimization.lotsizing.changeover.ChangeoverCostsSolution(problem: Problem)[source]

Bases: DemandsSolution[Item], Generic[Item]

Solution mixin for changeover cost computation.

compute_total_changeover_cost() float[source]

Compute total changeover cost based on production sequence.

Sum of changeover costs for consecutive items in the production sequence.

Returns:

Total changeover cost

get_changeover_count() int[source]

Get number of changeovers (switches between items).

Returns:

Number of times production switches from one item to another

abstractmethod get_production_sequence() list[tuple[int, Item]][source]

Get production sequence as list of (period, item) tuples.

The sequence should be sorted by period and include only periods where production actually occurs (setup happens).

Returns:

List of (period, item) tuples representing production sequence

problem: ChangeoverCostsProblem[Item]
class discrete_optimization.lotsizing.changeover.WithoutChangeoverCostsProblem[source]

Bases: ChangeoverCostsProblem[Item], Generic[Item]

Utility mixin for problems without changeover costs.

All changeover costs are zero - sequence doesn’t matter.

get_changeover_array() list[source]
has_changeover_costs() bool[source]

No changeover costs.

class discrete_optimization.lotsizing.changeover.WithoutChangeoverCostsSolution(problem: Problem)[source]

Bases: ChangeoverCostsSolution[Item], Generic[Item]

Solution mixin for problems without changeover costs.

compute_total_changeover_cost() float[source]

No changeover cost.

get_changeover_count() int[source]

Changeovers don’t matter without costs.

discrete_optimization.lotsizing.costs module

Cost structure mixins for lot sizing problems.

This module provides mixins for different cost components: - Setup costs (fixed cost when production occurs) - Production costs (variable cost per unit produced) - Inventory costs (holding cost per unit in stock)

class discrete_optimization.lotsizing.costs.CostsArrayProblem(setup_costs: ndarray | list[list[float]], production_costs: ndarray | list[list[float]], inventory_costs: ndarray | list[list[float]])[source]

Bases: SetupCostsProblem[Item], ProductionCostsProblem[Item], InventoryCostsProblem[Item], Generic[Item]

Concrete implementation using numpy arrays for all cost components.

This helper mixin stores costs as 2D arrays for efficient access.

Can be used as:
class MyProblem(CostsArrayProblem[int], OtherMixins…):
def __init__(self, setup_costs, production_costs, inventory_costs, …):
CostsArrayProblem.__init__(

self, setup_costs, production_costs, inventory_costs

get_inventory_cost_per_unit(item: Item, period: int) float[source]

Get inventory cost per unit from array storage.

get_production_cost_per_unit(item: Item, period: int) float[source]

Get production cost per unit from array storage.

get_setup_cost(item: Item, period: int) float[source]

Get setup cost from array storage.

class discrete_optimization.lotsizing.costs.InventoryCostsProblem[source]

Bases: DemandsProblem[Item], Generic[Item]

Mixin for problems with inventory holding costs.

Inventory cost c_it is the cost per unit of item i held in stock at end of period t. Total inventory cost = c_it * I_it where I_it is inventory level.

abstractmethod get_inventory_cost_per_unit(item: Item, period: int) float[source]

Get inventory holding cost per unit.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Inventory cost c_it per unit (non-negative)

class discrete_optimization.lotsizing.costs.InventoryCostsSolution(problem: Problem)[source]

Bases: DemandsSolution[Item], Generic[Item]

Solution mixin for inventory cost computation.

compute_total_inventory_cost() float[source]

Compute total inventory holding cost.

Returns:

Sum of c_it * I_it across all items and periods

problem: InventoryCostsProblem[Item]
class discrete_optimization.lotsizing.costs.ProductionCostsProblem[source]

Bases: DemandsProblem[Item], Generic[Item]

Mixin for problems with variable production costs.

Production cost v_it is the variable cost per unit of item i produced in period t. Total production cost = v_it * X_it where X_it is production quantity.

abstractmethod get_production_cost_per_unit(item: Item, period: int) float[source]

Get variable production cost per unit.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Production cost v_it per unit (non-negative)

class discrete_optimization.lotsizing.costs.ProductionCostsSolution(problem: Problem)[source]

Bases: DemandsSolution[Item], Generic[Item]

Solution mixin for production cost computation.

compute_total_production_cost() float[source]

Compute total variable production cost.

Returns:

Sum of v_it * X_it across all items and periods

problem: ProductionCostsProblem[Item]
class discrete_optimization.lotsizing.costs.SetupCostsProblem[source]

Bases: DemandsProblem[Item], Generic[Item]

Mixin for problems with setup costs.

Setup cost s_it is the fixed cost incurred when producing item i in period t. This cost is paid if Y_it = 1 (setup occurs), regardless of production quantity.

abstractmethod get_setup_cost(item: Item, period: int) float[source]

Get setup cost for producing item i in period t.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Setup cost s_it (non-negative)

class discrete_optimization.lotsizing.costs.SetupCostsSolution(problem: Problem)[source]

Bases: DemandsSolution[Item], Generic[Item]

Solution mixin for setup cost computation.

compute_total_setup_cost() float[source]

Compute total setup cost across all items and periods.

Returns:

Sum of all setup costs s_it * Y_it

abstractmethod has_setup(item: Item, period: int) bool[source]

Check if setup occurs (Y_it = 1).

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

True if setup occurs, False otherwise

problem: SetupCostsProblem[Item]
class discrete_optimization.lotsizing.costs.SingleItemCostsArrayProblem(setup_costs: ndarray | list[float], production_costs: ndarray | list[float], inventory_costs: ndarray | list[float])[source]

Bases: SetupCostsProblem[int], ProductionCostsProblem[int], InventoryCostsProblem[int]

Concrete implementation for single-item problems with 1D cost arrays.

Convenience class for single-item problems where costs are stored as 1D arrays. The items_list is fixed to [0].

get_inventory_cost_per_unit(item: int, period: int) float[source]

Get inventory cost per unit from 1D array.

get_production_cost_per_unit(item: int, period: int) float[source]

Get production cost per unit from 1D array.

get_setup_cost(item: int, period: int) float[source]

Get setup cost from 1D array.

property horizon: int

Horizon is length of cost arrays.

property items_list: list[int]

Single item with index 0.

class discrete_optimization.lotsizing.costs.WithoutInventoryCostsProblem[source]

Bases: InventoryCostsProblem[Item], Generic[Item]

Mixin for problems without inventory holding costs.

Use this when inventory can be held without cost (rare in practice). All inventory costs return 0.

get_inventory_cost_per_unit(item: Item, period: int) float[source]

No inventory costs - always returns 0.

class discrete_optimization.lotsizing.costs.WithoutInventoryCostsSolution(problem: Problem)[source]

Bases: InventoryCostsSolution[Item], Generic[Item]

Solution mixin for problems without inventory costs.

compute_total_inventory_cost() float[source]

No inventory costs - always returns 0.

problem: WithoutInventoryCostsProblem[Item]
class discrete_optimization.lotsizing.costs.WithoutProductionCostsProblem[source]

Bases: ProductionCostsProblem[Item], Generic[Item]

Mixin for problems without per-unit production costs.

Use this when production is limited only by capacity, not by per-unit costs. All production costs return 0.

get_production_cost_per_unit(item: Item, period: int) float[source]

No production costs - always returns 0.

class discrete_optimization.lotsizing.costs.WithoutProductionCostsSolution(problem: Problem)[source]

Bases: ProductionCostsSolution[Item], Generic[Item]

Solution mixin for problems without production costs.

compute_total_production_cost() float[source]

No production costs - always returns 0.

problem: WithoutProductionCostsProblem[Item]
class discrete_optimization.lotsizing.costs.WithoutSetupCostsProblem[source]

Bases: SetupCostsProblem[Item], Generic[Item]

Mixin for problems without setup costs.

Use this when there is no fixed cost to start production. All setup costs return 0.

get_setup_cost(item: Item, period: int) float[source]

No setup costs - always returns 0.

class discrete_optimization.lotsizing.costs.WithoutSetupCostsSolution(problem: Problem)[source]

Bases: SetupCostsSolution[Item], Generic[Item]

Solution mixin for problems without setup costs.

compute_total_setup_cost() float[source]

No setup costs - always returns 0.

problem: WithoutSetupCostsProblem[Item]

discrete_optimization.lotsizing.demands module

Demands mixin for lot sizing problems.

This module provides the core demands component that nearly all lot sizing problems use.

class discrete_optimization.lotsizing.demands.DemandsArrayProblem(demands: ndarray | list[list[int]])[source]

Bases: DemandsProblem[Item], Generic[Item]

Concrete implementation of DemandsProblem using numpy arrays for storage.

This is a helper mixin for concrete problem classes that want to store demands as a 2D array.

Can be used as:
class MyProblem(DemandsArrayProblem[int], OtherMixins…):
def __init__(self, demands, …):

DemandsArrayProblem.__init__(self, demands) …

get_demand(item: Item, period: int) int[source]

Get demand from array storage.

class discrete_optimization.lotsizing.demands.DemandsProblem[source]

Bases: LotSizingProblem[Item], Generic[Item]

Mixin for problems with demand requirements.

This is a core component - nearly all lot sizing problems have demands to satisfy.

The demand d_it represents the quantity of item i required in period t.

abstractmethod allows_lost_demand() bool[source]
get_cumulative_demands(item: Item) ndarray[source]

Get cumulative demand for item over time.

Useful for inventory and delivery computations.

Returns:

Array of cumulative demands [d_i0, d_i0+d_i1, d_i0+d_i1+d_i2, …]

abstractmethod get_demand(item: Item, period: int) int[source]

Get demand for given item in given period.

Parameters:
  • item – The product/item type

  • period – Time period (0 to horizon-1)

Returns:

Demand quantity d_it (non-negative integer)

get_max_demand_per_period() int[source]

Get maximum demand across all items and periods.

Useful for setting upper bounds in solvers.

Returns:

max_i,t d_it

get_total_demand(item: Item) int[source]

Get total demand for an item across all periods.

Returns:

Sum of all demands for this item

is_binary_demand()[source]
is_binary_demand_item(item: Item) bool[source]
class discrete_optimization.lotsizing.demands.DemandsSolution(problem: Problem)[source]

Bases: LotSizingSolution[Item], Generic[Item]

Solution mixin for demand-based problems.

Provides methods to check demand satisfaction.

check_demand_satisfaction(allow_delays: bool = False) bool[source]

Check whether all demands are eventually satisfied.

Parameters:

allow_delays – If False, demands must be satisfied on time (no backlog). If True, backlog is allowed but total satisfaction required.

Returns:

True if demands are satisfied according to policy, False otherwise

get_total_unmet_demand() int[source]

Compute total unmet demand across all items and periods.

Returns:

Total quantity of demand not satisfied

problem: DemandsProblem[Item]
class discrete_optimization.lotsizing.demands.SingleItemDemandsArrayProblem(demands: ndarray | list[int])[source]

Bases: DemandsProblem[int]

Concrete implementation for single-item problems with array storage.

This is a convenience class for single-item problems where demands can be stored as a 1D array.

The items_list is fixed to [0].

get_demand(item: int, period: int) int[source]

Get demand from 1D array.

property horizon: int

Horizon is length of demands array.

property items_list: list[int]

Single item with index 0.

discrete_optimization.lotsizing.generic_lotsizing module

Generic lot sizing problem composing all mixins.

This module provides GenericLotSizingProblem and GenericLotSizingSolution that combine all feature mixins, similar to GenericSchedulingProblem in generic_tasks_tools.

This generic class encompasses all lot sizing variants by composing mixins. Specific variants can disable features using “Without” mixins.

class discrete_optimization.lotsizing.generic_lotsizing.GenericLotSizingProblem[source]

Bases: SetupCostsProblem[Item], ProductionCostsProblem[Item], InventoryCostsProblem[Item], BacklogProblem[Item], ChangeoverCostsProblem[Item], StockLimitsProblem[Item], ParallelProductionProblem[Item], SetupTimesProblem[Item], Generic[Item]

Generic lot sizing problem with ALL optional features.

Similar to GenericSchedulingProblem in generic_tasks_tools, this class encompasses all lot sizing variants by composing mixins:

  • Single-item or multi-item: Controlled by items_list

  • Uncapacitated or capacitated: Use WithoutCapacityProblem for uncapacitated

  • With or without backlog: Use WithoutBacklogProblem if backlog not allowed

  • With or without setup times: Use WithoutSetupTimesProblem if setup times don’t consume capacity

  • With or without changeover costs: Use WithoutChangeoverCostsProblem for sequence-independent problems

  • With or without stock limits: Use WithoutStockLimitsProblem if no inventory limits

  • With or without parallel production: Use WithoutParallelProductionProblem if only one item per period

Each feature can be disabled using the corresponding “Without” mixin.

Example variants: - ULSP (Uncapacitated Lot-Sizing Problem): Use WithoutCapacityProblem - CLSP (Capacitated Lot-Sizing Problem): Use CapacityProblem - CLSP with setup times: Use SetupTimesProblem - CLSP with backlog: Use BacklogProblem with is_backlog_allowed() = True - CLSP with stock limits: Use StockLimitsProblem (or WithoutStockLimitsProblem to disable) - CLSP with exclusive production: Use WithoutParallelProductionProblem

evaluate(variable: GenericLotSizingSolution) dict[str, float][source]

Evaluate solution and compute all objective components.

Parameters:

variable – Solution to evaluate

Returns:

Dictionary with objective values

get_objective_register() ObjectiveRegister[source]

Define objectives for lot sizing problems.

Returns:

Objective register with setup, production, inventory, backlog, and changeover costs

satisfy(variable: GenericLotSizingSolution) bool[source]

Check all constraints.

Parameters:

variable – Solution to check

Returns:

True if all constraints satisfied, False otherwise

satisfy_partial(variable: GenericLotSizingSolution, demands: bool = True, capacity: bool = True, backlog: bool = True, stock_limits: bool = True, parallel_production: bool = True) bool[source]

Partial constraint checking.

One can switch off some checks by setting the corresponding parameter to False. Useful for debugging or progressive solution construction.

Parameters:
  • variable – Solution to check

  • demands – Check demand satisfaction

  • capacity – Check capacity constraints

  • backlog – Check backlog constraints

  • stock_limits – Check stock limit constraints

  • parallel_production – Check parallel production constraints

Returns:

True if selected constraints satisfied, False otherwise

class discrete_optimization.lotsizing.generic_lotsizing.GenericLotSizingSolution(problem: Problem)[source]

Bases: SetupCostsSolution[Item], ProductionCostsSolution[Item], InventoryCostsSolution[Item], BacklogSolution[Item], SetupTimesSolution[Item], ChangeoverCostsSolution[Item], StockLimitsSolution[Item], ParallelProductionSolution[Item], Generic[Item]

Generic lot sizing solution corresponding to GenericLotSizingProblem.

This solution class combines all mixin solution classes, providing: - Production and setup tracking - Inventory and delivery computation - Backlog tracking - Cost computation for all components - Constraint checking (capacity, stock limits, parallel production, etc.)

Concrete implementations should inherit from this and provide: - get_production_quantity() - has_setup() - get_delivery_quantity() - get_inventory_level() - get_backlog_quantity() - get_production_sequence()

compute_total_cost() float[source]

Compute total cost of all components.

Returns:

Sum of all cost components

get_cost_evolution() dict[str, list[float]][source]

Get cumulative cost evolution over time for all components.

Returns a dictionary with cumulative costs for each period: - ‘inventory’: Cumulative inventory holding costs - ‘backlog’: Cumulative backlog/delay costs - ‘setup’: Cumulative setup costs - ‘production’: Cumulative production costs - ‘changeover’: Cumulative changeover costs - ‘total’: Cumulative total cost

Returns:

Dictionary mapping cost component names to lists of cumulative costs

problem: GenericLotSizingProblem[Item]

discrete_optimization.lotsizing.parallel_production module

Parallel production constraint mixin for lot sizing problems.

This module provides mixins for problems where production of multiple items in the same time period may or may not be allowed.

class discrete_optimization.lotsizing.parallel_production.ParallelProductionProblem[source]

Bases: DemandsProblem[Item], Generic[Item]

Mixin for problems with constraints on parallel production.

Determines whether multiple items can be produced simultaneously in the same period.

When parallel production is NOT allowed, the constraint is:

sum_i Y_it <= 1 for all t

Where Y_it is the binary setup variable indicating if item i is produced in period t.

This models situations where: - Production line can only handle one product type at a time - Switching between items consumes the entire period - Production resources are exclusive (no multi-tasking)

When parallel production IS allowed, multiple items can be produced in the same period.

Relevant for multi-item problems. For single-item problems, this constraint is automatically satisfied.

abstractmethod allows_parallel_production() bool[source]

Check if multiple items can be produced in the same period.

Returns:

True if parallel production is allowed, False if only one item per period

class discrete_optimization.lotsizing.parallel_production.ParallelProductionSolution(problem: Problem)[source]

Bases: DemandsSolution[Item], Generic[Item]

Solution mixin for parallel production constraint checking.

Note: This mixin requires get_production_quantity(item, period) method to be available. In practice, this is provided by CapacitySolution or ProductionBasedSolution. Type checkers may warn about this - this is expected due to mixin composition.

check_parallel_production_constraints() bool[source]

Check if parallel production constraints are satisfied.

Returns:

True if constraint satisfied, False otherwise

count_item_switches() int[source]

Count the number of periods where production switches to a different item.

Useful for measuring setup frequency and production stability.

Returns:

Number of periods with item changes

get_items_produced_in_period(period: int) list[Item][source]

Get list of items produced in a given period.

Parameters:

period – Time period

Returns:

List of items with positive production in this period

get_periods_with_parallel_production() list[tuple[int, list[Item]]][source]

Get list of periods where multiple items are produced.

Useful for identifying violations when parallel production is not allowed, or for analysis when it is allowed.

Returns:

List of (period, items_produced) tuples where len(items_produced) > 1

problem: ParallelProductionProblem[Item]
class discrete_optimization.lotsizing.parallel_production.WithParallelProductionProblem[source]

Bases: ParallelProductionProblem[Item], Generic[Item]

Utility mixin for problems allowing parallel production.

Multiple items can be produced simultaneously in the same period.

This is the “With” variant for problems where parallel production of different items in the same period is allowed.

allows_parallel_production() bool[source]

Parallel production is allowed.

class discrete_optimization.lotsizing.parallel_production.WithParallelProductionSolution(problem: Problem)[source]

Bases: ParallelProductionSolution[Item], Generic[Item]

Solution mixin for problems allowing parallel production.

The parallel production constraint is always satisfied (not active).

check_parallel_production_constraints() bool[source]

Always satisfied when parallel production allowed.

class discrete_optimization.lotsizing.parallel_production.WithoutParallelProductionProblem[source]

Bases: ParallelProductionProblem[Item], Generic[Item]

Utility mixin for problems NOT allowing parallel production.

Only one item can be produced per period (exclusive production).

This is the “Without” variant following the generic_tasks_tools pattern.

allows_parallel_production() bool[source]

Parallel production is NOT allowed - only one item per period.

class discrete_optimization.lotsizing.parallel_production.WithoutParallelProductionSolution(problem: Problem)[source]

Bases: ParallelProductionSolution[Item], Generic[Item]

Solution mixin for problems NOT allowing parallel production.

Provides full constraint checking for the single-item-per-period restriction.

discrete_optimization.lotsizing.production_solution module

Generic production-based solution with inventory and backlog computation.

This module provides a base solution class that handles the core logic of computing inventory levels, deliveries, and backlog from production decisions. This should work for most lot sizing variants and provides a solid foundation for the mixin solutions.

class discrete_optimization.lotsizing.production_solution.DeliveryDecision(item: int, period: int, quantity: int)[source]

Bases: object

Represents a delivery decision.

item

Item/product type being delivered

Type:

int

period

Time period of delivery (0 to horizon-1)

Type:

int

quantity

Delivery quantity D_it

Type:

int

item: int
period: int
quantity: int
class discrete_optimization.lotsizing.production_solution.ProductionBasedSolution(problem: LotSizingProblem[Item], productions: list[ProductionDecision], deliveries: list[DeliveryDecision] | None = None)[source]

Bases: GenericLotSizingSolution[Item]

Generic solution based on production decisions.

This class provides a concrete implementation of GenericLotSizingSolution that automatically computes inventory, deliveries, and backlog from production decisions.

Key features: - Inventory levels computed over time - Delivery quantities to satisfy demands - Backlog quantities (delayed demands)

The computation follows the inventory balance equation:

I_it = I_i,t-1 + X_it - D_it

Where: - I_it: Inventory at end of period t - X_it: Production in period t - D_it: Delivery in period t (satisfying demand)

This implementation assumes: - Productions are provided as list of ProductionDecision objects - Demands are available via problem.get_demand() (from DemandsProblem mixin) - Deliveries are computed to satisfy demands ASAP from available stock

Subclasses can override delivery computation for different policies. Subclasses automatically get all GenericLotSizingSolution mixin methods (check_demand_satisfaction, check_capacity_constraints, compute_total_*_cost, etc.)

copy() ProductionBasedSolution[source]

Create a copy of this solution.

Returns:

New solution with copied production and delivery decisions

get_backlog_quantity(item: Item, period: int) int[source]

Get backlog quantity at end of period.

Backlog B_it is the cumulative demand not yet satisfied at end of period t.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Backlog quantity B_it

get_backlog_quantity_array(item: Item) ndarray[source]

Get backlog quantities for all periods for given item.

Parameters:

item – Item identifier

Returns:

Array of backlog quantities [B_i0, B_i1, …, B_i,T-1]

get_delivery_quantity(item: Item, period: int) int[source]

Get delivery quantity for given item and period.

Delivery quantity D_it is the amount delivered to satisfy demand in period t.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Delivery quantity D_it

get_delivery_quantity_array(item: Item) ndarray[source]

Get delivery quantities for all periods for given item.

Parameters:

item – Item identifier

Returns:

Array of delivery quantities [D_i0, D_i1, …, D_i,T-1]

get_inventory_level(item: Item, period: int) int[source]

Get inventory level at end of period.

Inventory I_it is the stock remaining at end of period t.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Inventory level I_it

get_inventory_level_array(item: Item) ndarray[source]

Get inventory levels for all periods for given item.

Parameters:

item – Item identifier

Returns:

Array of inventory levels [I_i0, I_i1, …, I_i,T-1]

get_production_quantity(item: Item, period: int) int[source]

Get production quantity for given item and period.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Production quantity X_it

get_production_quantity_array(item: Item) ndarray[source]

Get production quantities for all periods for given item.

Parameters:

item – Item identifier

Returns:

Array of production quantities [X_i0, X_i1, …, X_i,T-1]

get_production_sequence() list[tuple[int, Item]][source]

Get production sequence as list of (period, item) tuples.

Sorted by period, useful for computing changeover costs.

Returns:

List of (period, item) tuples where production occurs

has_setup(item: Item, period: int) bool[source]

Check if setup occurs for given item and period.

Setup occurs if production quantity > 0.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

True if setup Y_it = 1, False otherwise

invalidate_cache() None[source]

Invalidate cached computed values.

Call this when productions are modified externally.

lazy_copy() ProductionBasedSolution[source]

Create a lazy copy sharing production and delivery lists.

Warning: Modifying productions or deliveries will affect both solutions.

Returns:

New solution sharing production and delivery lists

problem: GenericLotSizingProblem[Item]
class discrete_optimization.lotsizing.production_solution.ProductionDecision(item: int, period: int, quantity: int)[source]

Bases: object

Represents a production decision.

item

Item/product type being produced

Type:

int

period

Time period of production (0 to horizon-1)

Type:

int

quantity

Production quantity X_it

Type:

int

setup

Whether a setup Y_it occurs (derived from quantity > 0)

item: int
period: int
quantity: int
property setup: bool

Setup occurs if production quantity > 0.

discrete_optimization.lotsizing.setup_times module

Setup times mixin for lot sizing problems.

This module provides mixins for problems where setup operations consume production capacity (in addition to production time).

class discrete_optimization.lotsizing.setup_times.SetupTimesProblem[source]

Bases: CapacityProblem[Item], Generic[Item]

Mixin for problems with setup times consuming capacity.

Setup time τ_it is the time required to setup production for item i in period t. This time is added to the capacity constraint:

sum_i (p_it * X_it + τ_it * Y_it) <= h_t

Where Y_it = 1 if setup occurs (X_it > 0).

get_max_production_quantity(item: Item, period: int) int[source]
abstractmethod get_setup_time(item: Item, period: int) float[source]

Get setup time τ_it.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Setup time (non-negative)

has_constant_setup(item: Item)[source]
class discrete_optimization.lotsizing.setup_times.SetupTimesSolution(problem: Problem)[source]

Bases: CapacitySolution[Item], Generic[Item]

Solution mixin for setup times in capacity constraints.

This extends CapacitySolution to include setup times in the capacity calculation.

get_total_production_time_used(period: int) float[source]

Override to include setup times in capacity usage.

Total time = sum_i (p_it * X_it + τ_it * Y_it)

Parameters:

period – Time period

Returns:

Total production time including setup times

problem: SetupTimesProblem[Item]
class discrete_optimization.lotsizing.setup_times.WithoutSetupTimesProblem[source]

Bases: SetupTimesProblem[Item], Generic[Item]

Utility mixin for problems without setup times.

Setup times are zero - setups don’t consume capacity.

get_setup_time(item: Item, period: int) float[source]

No setup time.

discrete_optimization.lotsizing.stock_limits module

Stock limits mixin for lot sizing problems.

This module provides mixins for problems with inventory stock limits. Stock limits constrain the maximum inventory that can be held for each item in each period.

class discrete_optimization.lotsizing.stock_limits.StockLimitsProblem[source]

Bases: DemandsProblem[Item], Generic[Item]

Mixin for problems with inventory stock limits.

Stock limits S_it constrain the maximum inventory that can be held:

I_it <= S_it

Where: - I_it: inventory level for item i at end of period t - S_it: maximum allowed stock for item i in period t

This can model warehouse capacity constraints, perishability limits, or other storage restrictions.

abstractmethod get_overall_stock_limit(period: int) int | float[source]
abstractmethod get_stock_limit_for_item(item: Item, period: int) int | float[source]

Get maximum inventory/stock limit for item in period.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Maximum allowed inventory S_it (non-negative, may be infinite)

has_overall_stock_limit(period: int) bool[source]
has_stock_limit_for_item(item: Item, period: int) bool[source]
has_stock_limits() bool[source]

Check if stock limits are active (any limit is finite).

Returns:

True if any stock limit is not infinite

class discrete_optimization.lotsizing.stock_limits.StockLimitsSolution(problem: Problem)[source]

Bases: DemandsSolution[Item], Generic[Item]

Solution mixin for stock limit constraint checking.

Note: This mixin requires get_inventory_level(item, period) method to be available. In practice, this is provided by InventoryCostsSolution or ProductionBasedSolution. Type checkers may warn about this - this is expected due to mixin composition.

check_stock_limit_constraints() bool[source]

Check if stock limits are satisfied in all periods.

Returns:

True if all stock limits satisfied, False otherwise

get_max_stock_utilization() float[source]

Get maximum stock utilization ratio across all items and periods.

Returns:

max_i,t (I_it / S_it), or 0 if no limits exist

get_stock_limit_violations() list[tuple[Item, int, float]][source]

Get list of stock limit violations.

Returns:

List of (item, period, excess) tuples where excess = inventory - limit

problem: StockLimitsProblem[Item]
class discrete_optimization.lotsizing.stock_limits.WithoutStockLimitsProblem[source]

Bases: StockLimitsProblem[Item], Generic[Item]

Utility mixin for problems without stock limits.

Returns infinite limits - no inventory constraints.

This is the “Without” variant following the generic_tasks_tools pattern. Use this when there are no warehouse capacity or storage constraints.

get_overall_stock_limit(period: int) int | float[source]
get_stock_limit_for_item(item: Item, period: int) float[source]

Infinite stock limit - no constraint.

has_stock_limits() bool[source]

No stock limits.

class discrete_optimization.lotsizing.stock_limits.WithoutStockLimitsSolution(problem: Problem)[source]

Bases: StockLimitsSolution[Item], Generic[Item]

Solution mixin for problems without stock limits.

Stock limit constraints are always satisfied (no constraints).

check_stock_limit_constraints() bool[source]

Always satisfied for unlimited stock.

get_max_stock_utilization() float[source]

Utilization is undefined for unlimited stock.

get_stock_limit_violations() list[tuple[Item, int, float]][source]

No violations when unlimited.

discrete_optimization.lotsizing.utils module

Visualization utilities for lot sizing solutions.

discrete_optimization.lotsizing.utils.plot_inventory_and_costs(problem: GenericLotSizingProblem, solution: GenericLotSizingSolution, figsize: tuple[float, float] = (14, 10)) plt.Figure[source]

Plot inventory levels and cumulated costs over time.

Creates a 2x2 subplot grid showing: 1. Inventory levels per item over time 2. Cumulated inventory cost over time 3. Backlog quantities per item over time 4. Cumulated costs (inventory + backlog + changeover) over time

Parameters:
  • problem – The lot sizing problem

  • solution – The solution to visualize

  • figsize – Figure size (width, height)

Returns:

Matplotlib figure

discrete_optimization.lotsizing.utils.plot_production_schedule(problem: GenericLotSizingProblem, solution: GenericLotSizingSolution, figsize: tuple[float, float] = (14, 6)) plt.Figure[source]

Plot production schedule with capacity constraints.

Shows stacked bar chart of: - Production quantities per item per period - Setup times (if applicable) - Available capacity as reference line

Parameters:
  • problem – The lot sizing problem

  • solution – The solution to visualize

  • figsize – Figure size (width, height)

Returns:

Matplotlib figure

discrete_optimization.lotsizing.utils.plot_solution_summary(problem: GenericLotSizingProblem, solution: GenericLotSizingSolution, figsize: tuple[float, float] = (16, 12)) plt.Figure[source]

Create comprehensive visualization of lot sizing solution.

Combines production schedule and cost tracking in one figure.

Parameters:
  • problem – The lot sizing problem

  • solution – The solution to visualize

  • figsize – Figure size (width, height)

Returns:

Matplotlib figure with 3 subplots

Module contents

Lot sizing module for discrete optimization.

This module provides a flexible mixin-based architecture for lot sizing problems, following the pattern from generic_tasks_tools.

Main classes: - GenericLotSizingProblem: Composition of all feature mixins - GenericLotSizingSolution: Solution class with all features - ProductionBasedSolution: Base solution with inventory/backlog computation

Mixins: - DemandsProblem/Solution: Demand requirements (core) - SetupCostsProblem/Solution: Setup costs - ProductionCostsProblem/Solution: Variable production costs - InventoryCostsProblem/Solution: Inventory holding costs - CapacityProblem/Solution: Production capacity constraints - BacklogProblem/Solution: Backlogged demand - SetupTimesProblem/Solution: Setup times consuming capacity - ChangeoverCostsProblem/Solution: Sequence-dependent changeover costs - StockLimitsProblem/Solution: Inventory stock limits - ParallelProductionProblem/Solution: Parallel production constraints

“Without” variants: - WithoutCapacityProblem/Solution: For uncapacitated problems - WithoutBacklogProblem/Solution: When backlog not allowed - WithoutSetupTimesProblem: When setup times don’t consume capacity - WithoutChangeoverCostsProblem/Solution: Sequence-independent problems - WithoutStockLimitsProblem/Solution: Unlimited inventory capacity - WithoutParallelProductionProblem/Solution: Only one item per period - WithParallelProductionProblem/Solution: Multiple items per period allowed

Example

>>> from discrete_optimization.lotsizing import (
...     GenericLotSizingProblem,
...     DemandsArrayProblem,
...     CostsArrayProblem,
...     WithoutCapacityProblem,
... )
>>> # Define uncapacitated single-item problem
>>> class MyProblem(
...     CostsArrayProblem[int],
...     DemandsArrayProblem[int],
...     WithoutCapacityProblem[int],
...     GenericLotSizingProblem[int],
... ):
...     pass
class discrete_optimization.lotsizing.BacklogProblem[source]

Bases: DemandsProblem[Item], Generic[Item]

Mixin for problems allowing backlogged demand.

Backlog B_it represents the cumulative demand not yet satisfied at end of period t. A cost b_it is incurred per unit of backlog.

When backlog is allowed, the demand satisfaction constraint is relaxed: instead of requiring delivery in period t, demand can be satisfied in later periods.

abstractmethod get_backlog_cost_per_unit(item: Item, period: int) float[source]

Get cost per unit of backlogged demand.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Backlog cost b_it per unit (non-negative)

abstractmethod is_backlog_allowed() bool[source]

Check whether backlog is allowed in this problem.

Returns:

True if backlog is permitted, False if demands must be satisfied on time

class discrete_optimization.lotsizing.BacklogSolution(problem: Problem)[source]

Bases: DemandsSolution[Item], Generic[Item]

Solution mixin for backlog handling.

check_backlog_constraints() bool[source]

Check backlog constraints.

If backlog is not allowed, verify that no backlog exists (all demands satisfied on time).

Returns:

True if constraints satisfied, False otherwise

compute_total_backlog_cost() float[source]

Compute total backlog cost across all items and periods.

Returns:

Sum of b_it * B_it

abstractmethod get_backlog_quantity(item: Item, period: int) int[source]

Get backlog quantity at end of period.

Backlog is the cumulative demand not yet satisfied:

B_it = max(0, cumulative_demand_it - cumulative_delivery_it)

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Backlog quantity B_it (non-negative integer)

get_max_backlog() int[source]

Get maximum backlog across all items and periods.

Useful for solution quality assessment.

Returns:

max_i,t B_it

get_total_backlog_at_period(period: int) int[source]

Get total backlog across all items at a given period.

Parameters:

period – Time period

Returns:

Sum of backlog for all items at this period

problem: BacklogProblem[Item]
class discrete_optimization.lotsizing.CapacityProblem[source]

Bases: DemandsProblem[Item], Generic[Item]

Mixin for problems with production capacity constraints.

Capacitated problems have a limit on total production time available in each period. The capacity constraint is typically:

sum_i (p_it * X_it) <= h_t

Where: - p_it: production time per unit of item i in period t - X_it: production quantity - h_t: available production time in period t

abstractmethod get_available_production_time(period: int) float[source]

Get available production time h_t in period t.

Parameters:

period – Time period

Returns:

Available capacity (non-negative, may be infinite for uncapacitated)

get_max_production_quantity(item: Item, period: int) int[source]
abstractmethod get_production_time_per_unit(item: Item, period: int) float[source]

Get production time per unit p_it.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Production time per unit (non-negative)

has_capacity_limits() bool[source]
has_constant_capacity()[source]
class discrete_optimization.lotsizing.CapacitySolution(problem: Problem)[source]

Bases: DemandsSolution[Item], Generic[Item]

Solution mixin for capacity constraint checking.

check_capacity_constraints() bool[source]

Check if capacity constraints are satisfied in all periods.

Returns:

True if capacity constraints satisfied, False otherwise

get_capacity_utilization(period: int) float[source]

Get capacity utilization ratio for a period.

Parameters:

period – Time period

Returns:

Ratio of used / available capacity (may be > 1 if violated)

get_total_production_time_used(period: int) float[source]

Compute total production time used in period.

This base implementation only considers production quantities. Subclasses (like SetupTimesSolution) may add setup times.

Parameters:

period – Time period

Returns:

Total production time used

problem: CapacityProblem[Item]
class discrete_optimization.lotsizing.ChangeoverCostsProblem[source]

Bases: DemandsProblem[Item], Generic[Item]

Mixin for sequence-dependent changeover costs.

Relevant for multi-item problems where the order of production matters. Changeover cost c_ij is the cost to switch from producing item i to item j.

This is different from setup costs which are item-specific and time-dependent. Changeover costs depend on the production sequence.

abstractmethod get_changeover_array() list[source]
get_changeover_cost(from_item: Item, to_item: Item) float[source]

Get sequence-dependent changeover cost.

Cost incurred when switching production from item i to item j.

Parameters:
  • from_item – Item produced previously

  • to_item – Item to be produced next

Returns:

Changeover cost c_ij (non-negative)

get_max_changeover_cost() float[source]
has_changeover_costs() bool[source]

Check if changeover costs are significant.

Returns:

True if any changeover cost is non-zero

class discrete_optimization.lotsizing.ChangeoverCostsSolution(problem: Problem)[source]

Bases: DemandsSolution[Item], Generic[Item]

Solution mixin for changeover cost computation.

compute_total_changeover_cost() float[source]

Compute total changeover cost based on production sequence.

Sum of changeover costs for consecutive items in the production sequence.

Returns:

Total changeover cost

get_changeover_count() int[source]

Get number of changeovers (switches between items).

Returns:

Number of times production switches from one item to another

abstractmethod get_production_sequence() list[tuple[int, Item]][source]

Get production sequence as list of (period, item) tuples.

The sequence should be sorted by period and include only periods where production actually occurs (setup happens).

Returns:

List of (period, item) tuples representing production sequence

problem: ChangeoverCostsProblem[Item]
class discrete_optimization.lotsizing.CostsArrayProblem(setup_costs: ndarray | list[list[float]], production_costs: ndarray | list[list[float]], inventory_costs: ndarray | list[list[float]])[source]

Bases: SetupCostsProblem[Item], ProductionCostsProblem[Item], InventoryCostsProblem[Item], Generic[Item]

Concrete implementation using numpy arrays for all cost components.

This helper mixin stores costs as 2D arrays for efficient access.

Can be used as:
class MyProblem(CostsArrayProblem[int], OtherMixins…):
def __init__(self, setup_costs, production_costs, inventory_costs, …):
CostsArrayProblem.__init__(

self, setup_costs, production_costs, inventory_costs

get_inventory_cost_per_unit(item: Item, period: int) float[source]

Get inventory cost per unit from array storage.

get_production_cost_per_unit(item: Item, period: int) float[source]

Get production cost per unit from array storage.

get_setup_cost(item: Item, period: int) float[source]

Get setup cost from array storage.

class discrete_optimization.lotsizing.DemandsArrayProblem(demands: ndarray | list[list[int]])[source]

Bases: DemandsProblem[Item], Generic[Item]

Concrete implementation of DemandsProblem using numpy arrays for storage.

This is a helper mixin for concrete problem classes that want to store demands as a 2D array.

Can be used as:
class MyProblem(DemandsArrayProblem[int], OtherMixins…):
def __init__(self, demands, …):

DemandsArrayProblem.__init__(self, demands) …

get_demand(item: Item, period: int) int[source]

Get demand from array storage.

class discrete_optimization.lotsizing.DemandsProblem[source]

Bases: LotSizingProblem[Item], Generic[Item]

Mixin for problems with demand requirements.

This is a core component - nearly all lot sizing problems have demands to satisfy.

The demand d_it represents the quantity of item i required in period t.

abstractmethod allows_lost_demand() bool[source]
get_cumulative_demands(item: Item) ndarray[source]

Get cumulative demand for item over time.

Useful for inventory and delivery computations.

Returns:

Array of cumulative demands [d_i0, d_i0+d_i1, d_i0+d_i1+d_i2, …]

abstractmethod get_demand(item: Item, period: int) int[source]

Get demand for given item in given period.

Parameters:
  • item – The product/item type

  • period – Time period (0 to horizon-1)

Returns:

Demand quantity d_it (non-negative integer)

get_max_demand_per_period() int[source]

Get maximum demand across all items and periods.

Useful for setting upper bounds in solvers.

Returns:

max_i,t d_it

get_total_demand(item: Item) int[source]

Get total demand for an item across all periods.

Returns:

Sum of all demands for this item

is_binary_demand()[source]
is_binary_demand_item(item: Item) bool[source]
class discrete_optimization.lotsizing.DemandsSolution(problem: Problem)[source]

Bases: LotSizingSolution[Item], Generic[Item]

Solution mixin for demand-based problems.

Provides methods to check demand satisfaction.

check_demand_satisfaction(allow_delays: bool = False) bool[source]

Check whether all demands are eventually satisfied.

Parameters:

allow_delays – If False, demands must be satisfied on time (no backlog). If True, backlog is allowed but total satisfaction required.

Returns:

True if demands are satisfied according to policy, False otherwise

get_total_unmet_demand() int[source]

Compute total unmet demand across all items and periods.

Returns:

Total quantity of demand not satisfied

problem: DemandsProblem[Item]
class discrete_optimization.lotsizing.GenericLotSizingProblem[source]

Bases: SetupCostsProblem[Item], ProductionCostsProblem[Item], InventoryCostsProblem[Item], BacklogProblem[Item], ChangeoverCostsProblem[Item], StockLimitsProblem[Item], ParallelProductionProblem[Item], SetupTimesProblem[Item], Generic[Item]

Generic lot sizing problem with ALL optional features.

Similar to GenericSchedulingProblem in generic_tasks_tools, this class encompasses all lot sizing variants by composing mixins:

  • Single-item or multi-item: Controlled by items_list

  • Uncapacitated or capacitated: Use WithoutCapacityProblem for uncapacitated

  • With or without backlog: Use WithoutBacklogProblem if backlog not allowed

  • With or without setup times: Use WithoutSetupTimesProblem if setup times don’t consume capacity

  • With or without changeover costs: Use WithoutChangeoverCostsProblem for sequence-independent problems

  • With or without stock limits: Use WithoutStockLimitsProblem if no inventory limits

  • With or without parallel production: Use WithoutParallelProductionProblem if only one item per period

Each feature can be disabled using the corresponding “Without” mixin.

Example variants: - ULSP (Uncapacitated Lot-Sizing Problem): Use WithoutCapacityProblem - CLSP (Capacitated Lot-Sizing Problem): Use CapacityProblem - CLSP with setup times: Use SetupTimesProblem - CLSP with backlog: Use BacklogProblem with is_backlog_allowed() = True - CLSP with stock limits: Use StockLimitsProblem (or WithoutStockLimitsProblem to disable) - CLSP with exclusive production: Use WithoutParallelProductionProblem

evaluate(variable: GenericLotSizingSolution) dict[str, float][source]

Evaluate solution and compute all objective components.

Parameters:

variable – Solution to evaluate

Returns:

Dictionary with objective values

get_objective_register() ObjectiveRegister[source]

Define objectives for lot sizing problems.

Returns:

Objective register with setup, production, inventory, backlog, and changeover costs

satisfy(variable: GenericLotSizingSolution) bool[source]

Check all constraints.

Parameters:

variable – Solution to check

Returns:

True if all constraints satisfied, False otherwise

satisfy_partial(variable: GenericLotSizingSolution, demands: bool = True, capacity: bool = True, backlog: bool = True, stock_limits: bool = True, parallel_production: bool = True) bool[source]

Partial constraint checking.

One can switch off some checks by setting the corresponding parameter to False. Useful for debugging or progressive solution construction.

Parameters:
  • variable – Solution to check

  • demands – Check demand satisfaction

  • capacity – Check capacity constraints

  • backlog – Check backlog constraints

  • stock_limits – Check stock limit constraints

  • parallel_production – Check parallel production constraints

Returns:

True if selected constraints satisfied, False otherwise

class discrete_optimization.lotsizing.GenericLotSizingSolution(problem: Problem)[source]

Bases: SetupCostsSolution[Item], ProductionCostsSolution[Item], InventoryCostsSolution[Item], BacklogSolution[Item], SetupTimesSolution[Item], ChangeoverCostsSolution[Item], StockLimitsSolution[Item], ParallelProductionSolution[Item], Generic[Item]

Generic lot sizing solution corresponding to GenericLotSizingProblem.

This solution class combines all mixin solution classes, providing: - Production and setup tracking - Inventory and delivery computation - Backlog tracking - Cost computation for all components - Constraint checking (capacity, stock limits, parallel production, etc.)

Concrete implementations should inherit from this and provide: - get_production_quantity() - has_setup() - get_delivery_quantity() - get_inventory_level() - get_backlog_quantity() - get_production_sequence()

compute_total_cost() float[source]

Compute total cost of all components.

Returns:

Sum of all cost components

get_cost_evolution() dict[str, list[float]][source]

Get cumulative cost evolution over time for all components.

Returns a dictionary with cumulative costs for each period: - ‘inventory’: Cumulative inventory holding costs - ‘backlog’: Cumulative backlog/delay costs - ‘setup’: Cumulative setup costs - ‘production’: Cumulative production costs - ‘changeover’: Cumulative changeover costs - ‘total’: Cumulative total cost

Returns:

Dictionary mapping cost component names to lists of cumulative costs

problem: GenericLotSizingProblem[Item]
class discrete_optimization.lotsizing.InventoryCostsProblem[source]

Bases: DemandsProblem[Item], Generic[Item]

Mixin for problems with inventory holding costs.

Inventory cost c_it is the cost per unit of item i held in stock at end of period t. Total inventory cost = c_it * I_it where I_it is inventory level.

abstractmethod get_inventory_cost_per_unit(item: Item, period: int) float[source]

Get inventory holding cost per unit.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Inventory cost c_it per unit (non-negative)

class discrete_optimization.lotsizing.InventoryCostsSolution(problem: Problem)[source]

Bases: DemandsSolution[Item], Generic[Item]

Solution mixin for inventory cost computation.

compute_total_inventory_cost() float[source]

Compute total inventory holding cost.

Returns:

Sum of c_it * I_it across all items and periods

problem: InventoryCostsProblem[Item]
class discrete_optimization.lotsizing.LotSizingProblem[source]

Bases: Problem, Generic[Item]

Minimal base class for all lot sizing problems.

This class only defines the essential structure common to ALL lot sizing variants: - Time horizon (number of periods) - Items/products to produce

All other features (demands, costs, capacity, etc.) are added via mixins.

Similar to TasksProblem in generic_tasks_tools.

get_index_from_item(item: Item) int[source]

Get index of item in items_list.

This is cached for efficiency when items_list doesn’t change.

Parameters:

item – Item identifier

Returns:

Index in items_list (0 to nb_items-1)

get_item_from_index(i: int) Item[source]

Get item from index.

Parameters:

i – Index in items_list

Returns:

Item identifier

abstract property horizon: int

Number of time periods T.

Periods are indexed from 0 to horizon-1.

abstract property items_list: list[Item]

List of all items (product types) to schedule production for.

Returns:

List of unique item identifiers

property nb_items: int

Number of different items/products.

update_items_list() None[source]

Call when items_list is updated to reset cache.

class discrete_optimization.lotsizing.LotSizingSolution(problem: Problem)[source]

Bases: Solution, Generic[Item]

Minimal base class for lot sizing solutions.

This is the base for all solution types. Specific solution representations are added by mixins and concrete implementations.

Similar to TasksSolution in generic_tasks_tools.

abstractmethod get_delivery_quantity(item: Item, period: int) int[source]

Get quantity of item delivered to satisfy demand in period.

This may differ from production quantity due to inventory.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Delivery quantity (amount used to satisfy demand in this period)

abstractmethod get_inventory_level(item: Item, period: int)[source]

Get inventory level at end of period.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Inventory level I_it (non-negative integer)

abstractmethod get_production_quantity(item: Item, period: int) int[source]

Get production quantity X_it.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Production quantity (non-negative integer)

get_total_delivery_quantity(item: Item) int[source]
get_total_production_quantity(item: Item) int[source]
problem: LotSizingProblem[Item]
class discrete_optimization.lotsizing.ParallelProductionProblem[source]

Bases: DemandsProblem[Item], Generic[Item]

Mixin for problems with constraints on parallel production.

Determines whether multiple items can be produced simultaneously in the same period.

When parallel production is NOT allowed, the constraint is:

sum_i Y_it <= 1 for all t

Where Y_it is the binary setup variable indicating if item i is produced in period t.

This models situations where: - Production line can only handle one product type at a time - Switching between items consumes the entire period - Production resources are exclusive (no multi-tasking)

When parallel production IS allowed, multiple items can be produced in the same period.

Relevant for multi-item problems. For single-item problems, this constraint is automatically satisfied.

abstractmethod allows_parallel_production() bool[source]

Check if multiple items can be produced in the same period.

Returns:

True if parallel production is allowed, False if only one item per period

class discrete_optimization.lotsizing.ParallelProductionSolution(problem: Problem)[source]

Bases: DemandsSolution[Item], Generic[Item]

Solution mixin for parallel production constraint checking.

Note: This mixin requires get_production_quantity(item, period) method to be available. In practice, this is provided by CapacitySolution or ProductionBasedSolution. Type checkers may warn about this - this is expected due to mixin composition.

check_parallel_production_constraints() bool[source]

Check if parallel production constraints are satisfied.

Returns:

True if constraint satisfied, False otherwise

count_item_switches() int[source]

Count the number of periods where production switches to a different item.

Useful for measuring setup frequency and production stability.

Returns:

Number of periods with item changes

get_items_produced_in_period(period: int) list[Item][source]

Get list of items produced in a given period.

Parameters:

period – Time period

Returns:

List of items with positive production in this period

get_periods_with_parallel_production() list[tuple[int, list[Item]]][source]

Get list of periods where multiple items are produced.

Useful for identifying violations when parallel production is not allowed, or for analysis when it is allowed.

Returns:

List of (period, items_produced) tuples where len(items_produced) > 1

problem: ParallelProductionProblem[Item]
class discrete_optimization.lotsizing.ProductionBasedSolution(problem: LotSizingProblem[Item], productions: list[ProductionDecision], deliveries: list[DeliveryDecision] | None = None)[source]

Bases: GenericLotSizingSolution[Item]

Generic solution based on production decisions.

This class provides a concrete implementation of GenericLotSizingSolution that automatically computes inventory, deliveries, and backlog from production decisions.

Key features: - Inventory levels computed over time - Delivery quantities to satisfy demands - Backlog quantities (delayed demands)

The computation follows the inventory balance equation:

I_it = I_i,t-1 + X_it - D_it

Where: - I_it: Inventory at end of period t - X_it: Production in period t - D_it: Delivery in period t (satisfying demand)

This implementation assumes: - Productions are provided as list of ProductionDecision objects - Demands are available via problem.get_demand() (from DemandsProblem mixin) - Deliveries are computed to satisfy demands ASAP from available stock

Subclasses can override delivery computation for different policies. Subclasses automatically get all GenericLotSizingSolution mixin methods (check_demand_satisfaction, check_capacity_constraints, compute_total_*_cost, etc.)

copy() ProductionBasedSolution[source]

Create a copy of this solution.

Returns:

New solution with copied production and delivery decisions

get_backlog_quantity(item: Item, period: int) int[source]

Get backlog quantity at end of period.

Backlog B_it is the cumulative demand not yet satisfied at end of period t.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Backlog quantity B_it

get_backlog_quantity_array(item: Item) ndarray[source]

Get backlog quantities for all periods for given item.

Parameters:

item – Item identifier

Returns:

Array of backlog quantities [B_i0, B_i1, …, B_i,T-1]

get_delivery_quantity(item: Item, period: int) int[source]

Get delivery quantity for given item and period.

Delivery quantity D_it is the amount delivered to satisfy demand in period t.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Delivery quantity D_it

get_delivery_quantity_array(item: Item) ndarray[source]

Get delivery quantities for all periods for given item.

Parameters:

item – Item identifier

Returns:

Array of delivery quantities [D_i0, D_i1, …, D_i,T-1]

get_inventory_level(item: Item, period: int) int[source]

Get inventory level at end of period.

Inventory I_it is the stock remaining at end of period t.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Inventory level I_it

get_inventory_level_array(item: Item) ndarray[source]

Get inventory levels for all periods for given item.

Parameters:

item – Item identifier

Returns:

Array of inventory levels [I_i0, I_i1, …, I_i,T-1]

get_production_quantity(item: Item, period: int) int[source]

Get production quantity for given item and period.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Production quantity X_it

get_production_quantity_array(item: Item) ndarray[source]

Get production quantities for all periods for given item.

Parameters:

item – Item identifier

Returns:

Array of production quantities [X_i0, X_i1, …, X_i,T-1]

get_production_sequence() list[tuple[int, Item]][source]

Get production sequence as list of (period, item) tuples.

Sorted by period, useful for computing changeover costs.

Returns:

List of (period, item) tuples where production occurs

has_setup(item: Item, period: int) bool[source]

Check if setup occurs for given item and period.

Setup occurs if production quantity > 0.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

True if setup Y_it = 1, False otherwise

invalidate_cache() None[source]

Invalidate cached computed values.

Call this when productions are modified externally.

lazy_copy() ProductionBasedSolution[source]

Create a lazy copy sharing production and delivery lists.

Warning: Modifying productions or deliveries will affect both solutions.

Returns:

New solution sharing production and delivery lists

problem: GenericLotSizingProblem[Item]
class discrete_optimization.lotsizing.ProductionCostsProblem[source]

Bases: DemandsProblem[Item], Generic[Item]

Mixin for problems with variable production costs.

Production cost v_it is the variable cost per unit of item i produced in period t. Total production cost = v_it * X_it where X_it is production quantity.

abstractmethod get_production_cost_per_unit(item: Item, period: int) float[source]

Get variable production cost per unit.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Production cost v_it per unit (non-negative)

class discrete_optimization.lotsizing.ProductionCostsSolution(problem: Problem)[source]

Bases: DemandsSolution[Item], Generic[Item]

Solution mixin for production cost computation.

compute_total_production_cost() float[source]

Compute total variable production cost.

Returns:

Sum of v_it * X_it across all items and periods

problem: ProductionCostsProblem[Item]
class discrete_optimization.lotsizing.ProductionDecision(item: int, period: int, quantity: int)[source]

Bases: object

Represents a production decision.

item

Item/product type being produced

Type:

int

period

Time period of production (0 to horizon-1)

Type:

int

quantity

Production quantity X_it

Type:

int

setup

Whether a setup Y_it occurs (derived from quantity > 0)

item: int
period: int
quantity: int
property setup: bool

Setup occurs if production quantity > 0.

class discrete_optimization.lotsizing.SetupCostsProblem[source]

Bases: DemandsProblem[Item], Generic[Item]

Mixin for problems with setup costs.

Setup cost s_it is the fixed cost incurred when producing item i in period t. This cost is paid if Y_it = 1 (setup occurs), regardless of production quantity.

abstractmethod get_setup_cost(item: Item, period: int) float[source]

Get setup cost for producing item i in period t.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Setup cost s_it (non-negative)

class discrete_optimization.lotsizing.SetupCostsSolution(problem: Problem)[source]

Bases: DemandsSolution[Item], Generic[Item]

Solution mixin for setup cost computation.

compute_total_setup_cost() float[source]

Compute total setup cost across all items and periods.

Returns:

Sum of all setup costs s_it * Y_it

abstractmethod has_setup(item: Item, period: int) bool[source]

Check if setup occurs (Y_it = 1).

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

True if setup occurs, False otherwise

problem: SetupCostsProblem[Item]
class discrete_optimization.lotsizing.SetupTimesProblem[source]

Bases: CapacityProblem[Item], Generic[Item]

Mixin for problems with setup times consuming capacity.

Setup time τ_it is the time required to setup production for item i in period t. This time is added to the capacity constraint:

sum_i (p_it * X_it + τ_it * Y_it) <= h_t

Where Y_it = 1 if setup occurs (X_it > 0).

get_max_production_quantity(item: Item, period: int) int[source]
abstractmethod get_setup_time(item: Item, period: int) float[source]

Get setup time τ_it.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Setup time (non-negative)

has_constant_setup(item: Item)[source]
class discrete_optimization.lotsizing.SetupTimesSolution(problem: Problem)[source]

Bases: CapacitySolution[Item], Generic[Item]

Solution mixin for setup times in capacity constraints.

This extends CapacitySolution to include setup times in the capacity calculation.

get_total_production_time_used(period: int) float[source]

Override to include setup times in capacity usage.

Total time = sum_i (p_it * X_it + τ_it * Y_it)

Parameters:

period – Time period

Returns:

Total production time including setup times

problem: SetupTimesProblem[Item]
class discrete_optimization.lotsizing.SingleItemCostsArrayProblem(setup_costs: ndarray | list[float], production_costs: ndarray | list[float], inventory_costs: ndarray | list[float])[source]

Bases: SetupCostsProblem[int], ProductionCostsProblem[int], InventoryCostsProblem[int]

Concrete implementation for single-item problems with 1D cost arrays.

Convenience class for single-item problems where costs are stored as 1D arrays. The items_list is fixed to [0].

get_inventory_cost_per_unit(item: int, period: int) float[source]

Get inventory cost per unit from 1D array.

get_production_cost_per_unit(item: int, period: int) float[source]

Get production cost per unit from 1D array.

get_setup_cost(item: int, period: int) float[source]

Get setup cost from 1D array.

property horizon: int

Horizon is length of cost arrays.

property items_list: list[int]

Single item with index 0.

class discrete_optimization.lotsizing.SingleItemDemandsArrayProblem(demands: ndarray | list[int])[source]

Bases: DemandsProblem[int]

Concrete implementation for single-item problems with array storage.

This is a convenience class for single-item problems where demands can be stored as a 1D array.

The items_list is fixed to [0].

get_demand(item: int, period: int) int[source]

Get demand from 1D array.

property horizon: int

Horizon is length of demands array.

property items_list: list[int]

Single item with index 0.

class discrete_optimization.lotsizing.StockLimitsProblem[source]

Bases: DemandsProblem[Item], Generic[Item]

Mixin for problems with inventory stock limits.

Stock limits S_it constrain the maximum inventory that can be held:

I_it <= S_it

Where: - I_it: inventory level for item i at end of period t - S_it: maximum allowed stock for item i in period t

This can model warehouse capacity constraints, perishability limits, or other storage restrictions.

abstractmethod get_overall_stock_limit(period: int) int | float[source]
abstractmethod get_stock_limit_for_item(item: Item, period: int) int | float[source]

Get maximum inventory/stock limit for item in period.

Parameters:
  • item – Item identifier

  • period – Time period

Returns:

Maximum allowed inventory S_it (non-negative, may be infinite)

has_overall_stock_limit(period: int) bool[source]
has_stock_limit_for_item(item: Item, period: int) bool[source]
has_stock_limits() bool[source]

Check if stock limits are active (any limit is finite).

Returns:

True if any stock limit is not infinite

class discrete_optimization.lotsizing.StockLimitsSolution(problem: Problem)[source]

Bases: DemandsSolution[Item], Generic[Item]

Solution mixin for stock limit constraint checking.

Note: This mixin requires get_inventory_level(item, period) method to be available. In practice, this is provided by InventoryCostsSolution or ProductionBasedSolution. Type checkers may warn about this - this is expected due to mixin composition.

check_stock_limit_constraints() bool[source]

Check if stock limits are satisfied in all periods.

Returns:

True if all stock limits satisfied, False otherwise

get_max_stock_utilization() float[source]

Get maximum stock utilization ratio across all items and periods.

Returns:

max_i,t (I_it / S_it), or 0 if no limits exist

get_stock_limit_violations() list[tuple[Item, int, float]][source]

Get list of stock limit violations.

Returns:

List of (item, period, excess) tuples where excess = inventory - limit

problem: StockLimitsProblem[Item]
class discrete_optimization.lotsizing.WithParallelProductionProblem[source]

Bases: ParallelProductionProblem[Item], Generic[Item]

Utility mixin for problems allowing parallel production.

Multiple items can be produced simultaneously in the same period.

This is the “With” variant for problems where parallel production of different items in the same period is allowed.

allows_parallel_production() bool[source]

Parallel production is allowed.

class discrete_optimization.lotsizing.WithParallelProductionSolution(problem: Problem)[source]

Bases: ParallelProductionSolution[Item], Generic[Item]

Solution mixin for problems allowing parallel production.

The parallel production constraint is always satisfied (not active).

check_parallel_production_constraints() bool[source]

Always satisfied when parallel production allowed.

class discrete_optimization.lotsizing.WithoutBacklogProblem[source]

Bases: BacklogProblem[Item], Generic[Item]

Utility mixin for problems without backlog.

This is the “Without” variant for problems where demands must be satisfied on time. Backlog costs are zero and backlog is not allowed.

get_backlog_cost_per_unit(item: Item, period: int) float[source]

No backlog cost.

is_backlog_allowed() bool[source]

Backlog not allowed.

class discrete_optimization.lotsizing.WithoutBacklogSolution(problem: Problem)[source]

Bases: BacklogSolution[Item], Generic[Item]

Solution mixin for problems without backlog.

All backlog quantities are zero.

check_backlog_constraints() bool[source]

Always satisfied (no backlog to check).

compute_total_backlog_cost() float[source]

No backlog cost.

get_backlog_quantity(item: Item, period: int) int[source]

No backlog.

get_max_backlog() int[source]

No backlog.

get_total_backlog_at_period(period: int) int[source]

No backlog.

class discrete_optimization.lotsizing.WithoutCapacityProblem[source]

Bases: CapacityProblem[Item], Generic[Item]

Utility mixin for uncapacitated problems.

Returns infinite capacity - no production time constraints.

This is the “Without” variant following the generic_tasks_tools pattern. Use this when the problem is uncapacitated (ULSP - Uncapacitated Lot-Sizing Problem).

get_available_production_time(period: int) float[source]

Infinite capacity available.

get_production_time_per_unit(item: Item, period: int) float[source]

No time per unit constraint in uncapacitated problems.

has_capacity_limits() bool[source]
class discrete_optimization.lotsizing.WithoutCapacitySolution(problem: Problem)[source]

Bases: CapacitySolution[Item], Generic[Item]

Solution mixin for uncapacitated problems.

Capacity constraints are always satisfied (no constraints).

check_capacity_constraints() bool[source]

Always satisfied for uncapacitated problems.

get_capacity_utilization(period: int) float[source]

Utilization is undefined for uncapacitated problems.

class discrete_optimization.lotsizing.WithoutChangeoverCostsProblem[source]

Bases: ChangeoverCostsProblem[Item], Generic[Item]

Utility mixin for problems without changeover costs.

All changeover costs are zero - sequence doesn’t matter.

get_changeover_array() list[source]
has_changeover_costs() bool[source]

No changeover costs.

class discrete_optimization.lotsizing.WithoutChangeoverCostsSolution(problem: Problem)[source]

Bases: ChangeoverCostsSolution[Item], Generic[Item]

Solution mixin for problems without changeover costs.

compute_total_changeover_cost() float[source]

No changeover cost.

get_changeover_count() int[source]

Changeovers don’t matter without costs.

class discrete_optimization.lotsizing.WithoutInventoryCostsProblem[source]

Bases: InventoryCostsProblem[Item], Generic[Item]

Mixin for problems without inventory holding costs.

Use this when inventory can be held without cost (rare in practice). All inventory costs return 0.

get_inventory_cost_per_unit(item: Item, period: int) float[source]

No inventory costs - always returns 0.

class discrete_optimization.lotsizing.WithoutInventoryCostsSolution(problem: Problem)[source]

Bases: InventoryCostsSolution[Item], Generic[Item]

Solution mixin for problems without inventory costs.

compute_total_inventory_cost() float[source]

No inventory costs - always returns 0.

problem: WithoutInventoryCostsProblem[Item]
class discrete_optimization.lotsizing.WithoutParallelProductionProblem[source]

Bases: ParallelProductionProblem[Item], Generic[Item]

Utility mixin for problems NOT allowing parallel production.

Only one item can be produced per period (exclusive production).

This is the “Without” variant following the generic_tasks_tools pattern.

allows_parallel_production() bool[source]

Parallel production is NOT allowed - only one item per period.

class discrete_optimization.lotsizing.WithoutParallelProductionSolution(problem: Problem)[source]

Bases: ParallelProductionSolution[Item], Generic[Item]

Solution mixin for problems NOT allowing parallel production.

Provides full constraint checking for the single-item-per-period restriction.

class discrete_optimization.lotsizing.WithoutProductionCostsProblem[source]

Bases: ProductionCostsProblem[Item], Generic[Item]

Mixin for problems without per-unit production costs.

Use this when production is limited only by capacity, not by per-unit costs. All production costs return 0.

get_production_cost_per_unit(item: Item, period: int) float[source]

No production costs - always returns 0.

class discrete_optimization.lotsizing.WithoutProductionCostsSolution(problem: Problem)[source]

Bases: ProductionCostsSolution[Item], Generic[Item]

Solution mixin for problems without production costs.

compute_total_production_cost() float[source]

No production costs - always returns 0.

problem: WithoutProductionCostsProblem[Item]
class discrete_optimization.lotsizing.WithoutSetupCostsProblem[source]

Bases: SetupCostsProblem[Item], Generic[Item]

Mixin for problems without setup costs.

Use this when there is no fixed cost to start production. All setup costs return 0.

get_setup_cost(item: Item, period: int) float[source]

No setup costs - always returns 0.

class discrete_optimization.lotsizing.WithoutSetupCostsSolution(problem: Problem)[source]

Bases: SetupCostsSolution[Item], Generic[Item]

Solution mixin for problems without setup costs.

compute_total_setup_cost() float[source]

No setup costs - always returns 0.

problem: WithoutSetupCostsProblem[Item]
class discrete_optimization.lotsizing.WithoutSetupTimesProblem[source]

Bases: SetupTimesProblem[Item], Generic[Item]

Utility mixin for problems without setup times.

Setup times are zero - setups don’t consume capacity.

get_setup_time(item: Item, period: int) float[source]

No setup time.

class discrete_optimization.lotsizing.WithoutStockLimitsProblem[source]

Bases: StockLimitsProblem[Item], Generic[Item]

Utility mixin for problems without stock limits.

Returns infinite limits - no inventory constraints.

This is the “Without” variant following the generic_tasks_tools pattern. Use this when there are no warehouse capacity or storage constraints.

get_overall_stock_limit(period: int) int | float[source]
get_stock_limit_for_item(item: Item, period: int) float[source]

Infinite stock limit - no constraint.

has_stock_limits() bool[source]

No stock limits.

class discrete_optimization.lotsizing.WithoutStockLimitsSolution(problem: Problem)[source]

Bases: StockLimitsSolution[Item], Generic[Item]

Solution mixin for problems without stock limits.

Stock limit constraints are always satisfied (no constraints).

check_stock_limit_constraints() bool[source]

Always satisfied for unlimited stock.

get_max_stock_utilization() float[source]

Utilization is undefined for unlimited stock.

get_stock_limit_violations() list[tuple[Item, int, float]][source]

No violations when unlimited.