Configuration

Detailed guide for configuring the linearization engine.

Overview

The LXLinearizerConfig class controls all aspects of the linearization process, from method selection to accuracy requirements.

Basic Configuration

Creating a Configuration

from lumix.linearization import LXLinearizerConfig, LXLinearizationMethod

# Default configuration
config = LXLinearizerConfig()

# Custom configuration
config = LXLinearizerConfig(
    default_method=LXLinearizationMethod.MCCORMICK,
    big_m_value=1e5,
    pwl_num_segments=30,
    adaptive_breakpoints=True,
    verbose_logging=True
)

Configuration Parameters

General Settings

default_method: LXLinearizationMethod = LXLinearizationMethod.MCCORMICK

Default linearization technique to use for bilinear products.

Available Methods:

  • MCCORMICK: McCormick envelopes (default, best for continuous variables)

  • BIG_M: Big-M method (for binary × continuous)

  • BINARY_EXPANSION: Binary expansion for integer products

  • SOS2: Special Ordered Set type 2 for piecewise functions

  • LOGARITHMIC: Logarithmic encoding for large integer products

Example:

# Use McCormick by default
config = LXLinearizerConfig(
    default_method=LXLinearizationMethod.MCCORMICK
)
tolerance: float = 1e-6

Numerical tolerance for comparisons and bound checking.

When Used:

  • Checking if bounds are equal

  • Validating linearization accuracy

  • Comparing breakpoint values

Example:

config = LXLinearizerConfig(tolerance=1e-8)
verbose_logging: bool = True

Enable detailed linearization logging for debugging and analysis.

What Gets Logged:

  • Detected nonlinear terms

  • Selected linearization techniques

  • Created auxiliary variables and constraints

  • Linearization statistics

Example:

# Enable verbose logging
config = LXLinearizerConfig(verbose_logging=True)

Big-M Settings

big_m_value: float = 1e6

Big-M constant for conditional constraints and Big-M linearization.

Critical Setting: Setting M too small can lead to incorrect solutions. Setting M too large can cause numerical issues and slow solving.

Choosing M:

  1. Problem-Specific: Use knowledge of variable bounds

  2. Conservative: Use 100× the maximum expected value

  3. Validation: Verify solutions don’t hit M bounds

Example:

# For variables bounded in [0, 1000]
config = LXLinearizerConfig(big_m_value=1e5)

# For normalized variables in [0, 1]
config = LXLinearizerConfig(big_m_value=100)

Piecewise-Linear Settings

pwl_num_segments: int = 20

Number of linear segments for piecewise-linear approximations.

Accuracy vs. Complexity:

  • More segments → better accuracy

  • More segments → more variables and constraints

  • Typical range: 10-50 segments

Guidelines:

Function Type

Segments

Reason

Smooth (sqrt, sin, cos)

10-20

Uniform approximation sufficient

Curved (exp, log, sigmoid)

30-50

Sharp curvature needs more points

Custom functions

20-40

Depends on curvature

Example:

# High accuracy for exponential
config = LXLinearizerConfig(pwl_num_segments=50)
pwl_method: Literal['sos2', 'incremental', 'logarithmic'] = "sos2"

Method for piecewise-linear formulation.

Methods:

  1. SOS2 (Special Ordered Set type 2): - Best when solver supports SOS2 - Fewest variables (n+1 continuous) - Recommended for Gurobi, CPLEX

  2. Incremental: - Uses binary selection variables - More variables but standard MILP - Recommended for solvers without SOS2

  3. Logarithmic (Gray code): - Uses log₂(n) binary variables - Best for many segments (>100) - Not yet implemented in LumiX

Example:

# Use SOS2 if solver supports it
config = LXLinearizerConfig(
    pwl_method="sos2",
    prefer_sos2=True
)

# Use incremental for GLPK
config = LXLinearizerConfig(pwl_method="incremental")
prefer_sos2: bool = True

Use SOS2 formulation when solver supports it, regardless of pwl_method.

Auto-Detection:

The linearizer checks solver capabilities and automatically uses SOS2 if: - prefer_sos2=True - Solver supports SOS2 (Gurobi, CPLEX, some OR-Tools modes)

Example:

config = LXLinearizerConfig(
    prefer_sos2=True  # Use SOS2 if available
)
adaptive_breakpoints: bool = True

Use adaptive breakpoint generation based on function curvature.

How It Works:

  • Samples function at many points

  • Computes second derivative (curvature measure)

  • Concentrates breakpoints where curvature is high

Benefits:

  • Better accuracy with same number of segments

  • Automatically adapts to function shape

  • Especially useful for functions with varying curvature

When to Use:

  • Curved functions (exp, log, sigmoid): adaptive=True

  • Smooth functions (sqrt, linear pieces): adaptive=False (uniform is fine)

Example:

# Adaptive for exponential function
config = LXLinearizerConfig(
    pwl_num_segments=30,
    adaptive_breakpoints=True
)

McCormick Envelope Settings

auto_detect_bounds: bool = True

Automatically detect variable bounds for McCormick envelopes.

How It Works:

  • Checks variable lower_bound and upper_bound attributes

  • Falls back to default bounds if not specified

  • Raises error if bounds cannot be determined

Example:

config = LXLinearizerConfig(auto_detect_bounds=True)

# Variables must have bounds
x = LXVariable[Product, float]("x").bounds(lower=0, upper=100)
y = LXVariable[Product, float]("y").bounds(lower=-50, upper=50)
mccormick_tighten_bounds: bool = True

Apply bound tightening preprocessing for McCormick envelopes.

What It Does:

  • Tightens bounds using constraint propagation

  • Results in stronger linear relaxation

  • Improves solver performance

Trade-off:

  • Small preprocessing overhead

  • Significant solving time improvement

Example:

# Enable bound tightening (recommended)
config = LXLinearizerConfig(
    mccormick_tighten_bounds=True
)

Binary Expansion Settings

binary_expansion_bits: int = 10

Number of bits for binary expansion method.

Purpose:

Linearize integer × integer products by representing integers in binary.

Capacity:

  • bits=10 → integers up to 2¹⁰ = 1024

  • bits=15 → integers up to 2¹⁵ = 32,768

  • bits=20 → integers up to 2²⁰ = 1,048,576

Variables Created:

  • For product of two integers: 2 × bits binary variables

Example:

# For integers up to 1000
config = LXLinearizerConfig(binary_expansion_bits=10)

# For larger integers up to 100,000
config = LXLinearizerConfig(binary_expansion_bits=17)

Configuration Examples

Production Environment

Optimized for solve time and numerical stability:

production_config = LXLinearizerConfig(
    # Use proven methods
    default_method=LXLinearizationMethod.MCCORMICK,
    pwl_method="sos2",

    # Tight M values (problem-specific)
    big_m_value=1e4,  # Based on domain knowledge

    # Balanced accuracy
    pwl_num_segments=25,
    adaptive_breakpoints=True,

    # Enable optimizations
    mccormick_tighten_bounds=True,
    prefer_sos2=True,

    # Moderate logging
    verbose_logging=False,

    # Standard tolerance
    tolerance=1e-6
)

Research / Prototyping

High accuracy for validation and experimentation:

research_config = LXLinearizerConfig(
    # High accuracy
    pwl_num_segments=50,
    adaptive_breakpoints=True,

    # Conservative Big-M
    big_m_value=1e6,

    # Detailed logging
    verbose_logging=True,

    # Tight tolerance
    tolerance=1e-8,

    # Best formulations
    prefer_sos2=True,
    mccormick_tighten_bounds=True
)

Memory-Constrained

Minimize auxiliary variables and constraints:

memory_config = LXLinearizerConfig(
    # Fewer segments
    pwl_num_segments=10,
    adaptive_breakpoints=True,  # Get more from fewer segments

    # Prefer techniques with fewer variables
    pwl_method="sos2",  # Fewer vars than incremental
    prefer_sos2=True,

    # Minimal logging
    verbose_logging=False
)

Solver-Specific Configurations

Gurobi / CPLEX

Leverage advanced solver features:

advanced_solver_config = LXLinearizerConfig(
    # Use SOS2 (natively supported)
    pwl_method="sos2",
    prefer_sos2=True,

    # Can use smaller Big-M (better presolve)
    big_m_value=1e4,

    # Enable all optimizations
    mccormick_tighten_bounds=True,
    auto_detect_bounds=True
)

GLPK / Basic Solvers

No SOS2 support, use standard MILP:

basic_solver_config = LXLinearizerConfig(
    # Use incremental (no SOS2 in GLPK)
    pwl_method="incremental",
    prefer_sos2=False,

    # Fewer segments (slower with incremental)
    pwl_num_segments=15,

    # Standard settings
    big_m_value=1e5,
    adaptive_breakpoints=True
)

Validation and Debugging

Checking Configuration

config = LXLinearizerConfig(
    pwl_num_segments=30,
    verbose_logging=True
)

# Validate settings
assert config.pwl_num_segments > 0, "Need at least one segment"
assert config.tolerance > 0, "Tolerance must be positive"
assert config.big_m_value > 0, "Big-M must be positive"

Logging Output

With verbose_logging=True, you’ll see:

[Linearization] Scanning model for nonlinear terms...
[Linearization] Found 3 bilinear terms
[Linearization] Found 2 piecewise-linear terms
[Linearization] Linearizing bilinear term: price[p1] * quantity[p1]
[Linearization] Using McCormick envelopes (continuous × continuous)
[Linearization] Created auxiliary variable: aux_mccormick_price_quantity_1
[Linearization] Created 4 McCormick constraints
[Linearization] Summary:
[Linearization]   - Bilinear terms: 3
[Linearization]   - Piecewise terms: 2
[Linearization]   - Auxiliary variables: 8
[Linearization]   - Auxiliary constraints: 17

See Also