CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pulp

PuLP is a linear and mixed integer programming modeler that provides an intuitive Python interface for creating, manipulating, and solving mathematical optimization problems.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

utility-functions.mddocs/

Utility Functions

Supporting functions for combinatorial operations, data structure manipulation, and system utilities that enhance PuLP's modeling capabilities. These utilities provide essential tools for complex optimization problem formulation and data handling.

Capabilities

Data Structure Functions

Functions for creating and manipulating dictionaries and structured data, particularly useful for organizing variables and parameters in large-scale optimization problems.

def makeDict(headers, array, default=None):
    """
    Create a dictionary from column headers and data array.
    
    Parameters:
    - headers (list): List of header names for dictionary keys
    - array (list of lists): Data rows where each row contains values for headers
    - default: Default value for missing entries
    
    Returns:
    dict: Dictionary with headers as keys and corresponding data as values
    
    Examples:
    headers = ['name', 'cost', 'capacity']
    data = [['plant1', 100, 500], ['plant2', 120, 600]]
    result = makeDict(headers, data)
    # Returns: {'name': ['plant1', 'plant2'], 'cost': [100, 120], 'capacity': [500, 600]}
    """

def splitDict(data):
    """
    Split a dictionary containing lists into multiple dictionaries.
    
    Parameters:
    - data (dict): Dictionary where values are lists of equal length
    
    Returns:
    list: List of dictionaries, one for each index position
    
    Examples:
    data = {'name': ['A', 'B'], 'cost': [10, 20], 'capacity': [100, 200]}
    result = splitDict(data)
    # Returns: [{'name': 'A', 'cost': 10, 'capacity': 100}, 
    #          {'name': 'B', 'cost': 20, 'capacity': 200}]
    """

def read_table(data, coerce_type, transpose=False):
    """
    Read table data into dictionary structure with type coercion.
    
    Parameters:
    - data: Input data in various formats (list of lists, nested structure)
    - coerce_type: Function or type to apply to data elements
    - transpose (bool): Whether to transpose the data structure
    
    Returns:
    dict: Processed data dictionary
    
    Examples:
    data = [['1', '2'], ['3', '4']]
    result = read_table(data, int)
    # Converts string data to integers
    """

Usage examples:

# Organize problem data
facilities = ['F1', 'F2', 'F3']
costs = [100, 150, 120]
capacities = [500, 600, 400]

# Create structured data dictionary
facility_data = makeDict(['facility', 'cost', 'capacity'], 
                        [facilities, costs, capacities])

# Split into individual facility records
facility_records = splitDict(facility_data)
for record in facility_records:
    print(f"Facility {record['facility']}: cost={record['cost']}, capacity={record['capacity']}")

# Process CSV-like data for optimization
raw_data = [
    ['10', '20', '30'],
    ['15', '25', '35'],
    ['12', '22', '32']
]
cost_matrix = read_table(raw_data, float)

# Use in variable creation
plants = list(facility_data['facility'])
production = LpVariable.dicts('prod', plants, 0)

# Create cost constraints using structured data
for i, plant in enumerate(plants):
    prob += facility_data['cost'][i] * production[plant] <= facility_data['capacity'][i]

Combinatorial Functions

Functions for generating combinations and permutations, essential for modeling complex assignment and scheduling problems.

def allcombinations(orgset, k):
    """
    Generate all combinations of elements from orgset with up to k items.
    
    Parameters:
    - orgset (iterable): Set of elements to combine
    - k (int): Maximum number of elements in each combination
    
    Returns:
    list: List of all combinations as tuples
    
    Examples:
    allcombinations(['A', 'B', 'C'], 2)
    # Returns: [(), ('A',), ('B',), ('C',), ('A', 'B'), ('A', 'C'), ('B', 'C')]
    """

def allpermutations(orgset, k):
    """
    Generate all permutations of elements from orgset with up to k items.
    
    Parameters:
    - orgset (iterable): Set of elements to permute
    - k (int): Maximum number of elements in each permutation
    
    Returns:
    list: List of all permutations as tuples
    
    Examples:
    allpermutations(['A', 'B'], 2)
    # Returns: [(), ('A',), ('B',), ('A', 'B'), ('B', 'A')]
    """

def combination(iterable, r):
    """
    Alias for itertools.combinations - generate r-length combinations.
    
    Parameters:
    - iterable: Elements to combine
    - r (int): Length of each combination
    
    Returns:
    itertools.combinations: Iterator of r-length combinations
    """

def permutation(iterable, r):
    """
    Alias for itertools.permutations - generate r-length permutations.
    
    Parameters:
    - iterable: Elements to permute  
    - r (int): Length of each permutation
    
    Returns:
    itertools.permutations: Iterator of r-length permutations  
    """

Usage examples:

from itertools import combinations, permutations

# Assignment problem - select teams for projects
teams = ['TeamA', 'TeamB', 'TeamC', 'TeamD']
projects = ['Proj1', 'Proj2', 'Proj3']

# All possible assignments of 2 teams to each project
team_combinations = list(combination(teams, 2))
for combo in team_combinations:
    for project in projects:
        # Create binary variable for each team combination-project pair
        var_name = f"assign_{combo[0]}_{combo[1]}_{project}"
        assignment_var = LpVariable(var_name, cat=LpBinary)

# Scheduling problem - all possible orderings
tasks = ['TaskA', 'TaskB', 'TaskC']
all_sequences = list(permutation(tasks, len(tasks)))

# Create variables for each possible sequence
sequence_vars = {}
for i, seq in enumerate(all_sequences):
    sequence_vars[seq] = LpVariable(f"sequence_{i}", cat=LpBinary)

# Constraint: exactly one sequence must be selected
prob += lpSum(sequence_vars.values()) == 1

# Resource allocation with combinations
resources = ['R1', 'R2', 'R3', 'R4']
max_resources_per_task = 2

# All valid resource combinations for tasks
valid_combinations = list(allcombinations(resources, max_resources_per_task))
for task in tasks:
    task_resource_vars = {}
    for combo in valid_combinations:
        if combo:  # Skip empty combination
            var_name = f"use_{task}_{'_'.join(combo)}"
            task_resource_vars[combo] = LpVariable(var_name, cat=LpBinary)
    
    # Each task must use exactly one resource combination
    if task_resource_vars:
        prob += lpSum(task_resource_vars.values()) == 1

Value and Type Checking Functions

Functions for handling numeric values and type validation in optimization contexts.

def valueOrDefault(x):
    """
    Get the value of a variable/expression or return a default within bounds.
    
    Parameters:
    - x (LpVariable or LpAffineExpression): Object to evaluate
    
    Returns:
    float: Value of x, or a default value if not solved
    
    Note: For variables, returns a value within the variable's bounds.
    For expressions, returns the constant term or calculated default.
    """

def isNumber(x):
    """
    Check if x is a numeric value (int or float).
    
    Parameters:
    - x: Object to check
    
    Returns:
    bool: True if x is int or float, False otherwise
    """

Usage examples:

# Robust value extraction after solving
variables = [x, y, z]
solution_values = {}

for var in variables:
    val = value(var)
    if val is not None:
        solution_values[var.name] = val
    else:
        # Use default value within bounds
        solution_values[var.name] = valueOrDefault(var)

# Type validation for parameters
def create_cost_constraint(variables, costs, limit):
    # Validate that all costs are numeric
    if not all(isNumber(cost) for cost in costs):
        raise ValueError("All costs must be numeric")
    
    # Create constraint
    total_cost = lpDot(variables, costs)
    return total_cost <= limit

# Safe arithmetic operations
def safe_multiply(var, coeff):
    if isNumber(coeff):
        return coeff * var
    else:
        raise TypeError(f"Coefficient must be numeric, got {type(coeff)}")

System Utilities

Functions for performance monitoring and system resource tracking.

def resource_clock():
    """
    Return the current resource usage time for performance monitoring.
    
    Returns:
    float: Resource time in seconds
    
    Note: Used for tracking solver performance and optimization runtime.
    """

Usage examples:

# Performance monitoring for optimization
start_time = resource_clock()

# Build and solve problem
prob = LpProblem("Performance_Test", LpMinimize)
variables = LpVariable.dicts("x", range(1000), 0, 1)
prob += lpSum(variables)

# Add many constraints
for i in range(500):
    prob += lpSum(variables[j] for j in range(i, min(i+10, 1000))) <= 5

solve_start = resource_clock()
status = prob.solve()
solve_time = resource_clock() - solve_start
total_time = resource_clock() - start_time

print(f"Model building time: {solve_start - start_time:.3f} seconds")
print(f"Solve time: {solve_time:.3f} seconds") 
print(f"Total time: {total_time:.3f} seconds")

# Benchmark different approaches
def benchmark_approach(approach_func, *args):
    start = resource_clock()
    result = approach_func(*args)
    elapsed = resource_clock() - start
    return result, elapsed

# Compare different formulation methods
formulation1_result, time1 = benchmark_approach(create_formulation_v1, data)
formulation2_result, time2 = benchmark_approach(create_formulation_v2, data)

print(f"Formulation 1: {time1:.3f}s")
print(f"Formulation 2: {time2:.3f}s")
if time1 < time2:
    print("Formulation 1 is faster")
else:
    print("Formulation 2 is faster")

Advanced Data Processing

Complex data manipulation patterns for large-scale optimization problems.

# Multi-dimensional data organization
def organize_transportation_data(supply_points, demand_points, costs, capacities, demands):
    """
    Organize transportation problem data into structured format.
    """
    # Create cost matrix
    cost_data = {}
    for i, supply in enumerate(supply_points):
        cost_data[supply] = {}
        for j, demand in enumerate(demand_points):
            cost_data[supply][demand] = costs[i][j]
    
    # Combine with capacity and demand data
    supply_data = dict(zip(supply_points, capacities))
    demand_data = dict(zip(demand_points, demands))
    
    return cost_data, supply_data, demand_data

# Use organized data in optimization
cost_matrix, supply_capacity, demand_requirement = organize_transportation_data(
    ['S1', 'S2', 'S3'], 
    ['D1', 'D2', 'D3', 'D4'],
    [[10, 15, 20, 25], [12, 18, 22, 28], [8, 14, 16, 30]],
    [100, 150, 120],
    [80, 90, 100, 70]
)

# Create transportation variables and constraints
transport_vars = LpVariable.matrix("transport", 
                                 list(supply_capacity.keys()),
                                 list(demand_requirement.keys()), 0)

# Supply constraints
for supply_point in supply_capacity:
    prob += lpSum([transport_vars[supply_point][demand_point] 
                   for demand_point in demand_requirement]) <= supply_capacity[supply_point]

# Demand constraints  
for demand_point in demand_requirement:
    prob += lpSum([transport_vars[supply_point][demand_point] 
                   for supply_point in supply_capacity]) >= demand_requirement[demand_point]

# Objective function using organized cost data
total_cost = lpSum([cost_matrix[s][d] * transport_vars[s][d] 
                    for s in supply_capacity 
                    for d in demand_requirement])
prob += total_cost

Install with Tessl CLI

npx tessl i tessl/pypi-pulp

docs

constants-enums.md

core-modeling.md

file-io.md

index.md

mathematical-operations.md

solver-interfaces.md

utility-functions.md

tile.json