Skip to main content

folf

folf computes Edmundson-Madansky (UB) and Jensen-based (LB) piecewise linear approximations suitable for embedding the first order loss function in mixed-integer linear optimization models.

CI codecov PyPI PyPI - Wheel GitHub last commit Downloads Python License: MIT Code style: Black Lint: Ruff Type Checked: mypy

Loss function piecewise linearisation

Features

  • Empirical first-order and complementary first-order loss functions for sums of independent SciPy distributions, with series, plotting, and CSV export
  • Simple random and Latin hypercube sampling, including empirical loss functions for weighted scalar products of random variables
  • Exact closed-form loss functions for scalar projections of multivariate normal demand, using either full covariance or independent-demand variance
  • Uniform and minimax Jensen partitions for standard normal demand, including partition probabilities, conditional means, and maximum approximation error
  • Numerically stable partitioning and linearisation calculations, with tail-safe normal probabilities, log-space breakpoints, and tolerance-aware mass allocation
  • Empirical Jensen piecewise linear lower approximations for both loss-function orientations, with pointwise and maximum error calculations
  • Cached standard normal linearization data and automatic selection of segment and variance-partition counts for a requested error tolerance

Who This Is For

This library is useful when you need approximate or empirical first-order loss functions for inventory and stochastic optimization workflows, especially with normal or sampled demand models.

References

R. Rossi, S. A. Tarim, B. Hnich, and S. Prestwich, "Piecewise linear lower and upper bounds for the standard normal first order loss function," Applied Mathematics and Computation, Elsevier, vol. 231, pp. 489-502, 2014.

R. Rossi, E.M.T. Hendrix, "Computing linearisation parameters of arbitrarily distributed first order loss functions," in Proceedings of MAGO'14, XII Global Optimization Workshop (GOW).

R. Rossi, S. Prestwich, and S. A. Tarim, "Mixed-Integer Linear Programming Approximations for the Stochastic Knapsack," Computers & Operations Research, Elsevier, Vol. 194: 107571, 2026.

Installation

pip install -e .

Command-line usage:

folf-cli --help

For development:

pip install -e .[dev]

Quick Start

CLI: Plot a loss function and its piecewise linearisation

folf-cli plot-loss \
	--distribution poisson:20 \
	--distribution norm:8:2 \
	--distribution gamma:4:1.5 \
	--sampling LHS \
	--samples 5000 \
	--x-min 10 \
	--x-max 60 \
	--precision 0.5 \
	--piecewise-masses 0.25,0.25,0.25,0.25 \
	--loss-type complementary \
	--output artifacts/loss_piecewise.png

Supported distributions in CLI:

  • poisson:<lambda>
  • norm:<mu>:<sigma>
  • gamma:<shape>:<scale>

The command produces a plot with:

  • Empirical loss function curve
  • Piecewise linearisation curve

1. Empirical first-order loss from sampled distributions

from scipy.stats import gamma, norm, poisson

from folf import FirstOrderLossFunction
from folf.utilities.probability.sampling import SAMPLING

folf = FirstOrderLossFunction(
	distributions=[
		poisson(20),      # discrete demand component
		norm(8, 2),       # approximately normal component
		gamma(a=4, scale=1.5),  # right-skewed positive component
	],
	sampling_strategy=SAMPLING.SRS,
)

x = 70.0
nb_samples = 5_000

complementary = folf.get_complementary_first_order_loss_function_value(x, nb_samples)
regular = folf.get_first_order_loss_function_value(x, nb_samples)

print("CL(x):", complementary)
print("L(x):", regular)

1b. Compare SRS vs LHS sampling strategies

from scipy.stats import gamma, norm, poisson

from folf import FirstOrderLossFunction
from folf.utilities.probability.sampling import SAMPLING

distributions = [
	poisson(20),
	norm(8, 2),
	gamma(a=4, scale=1.5),
]

srs_model = FirstOrderLossFunction(distributions, sampling_strategy=SAMPLING.SRS)
lhs_model = FirstOrderLossFunction(distributions, sampling_strategy=SAMPLING.LHS)

x = 70.0
nb_samples = 2_000

cl_srs = srs_model.get_complementary_first_order_loss_function_value(x, nb_samples)
cl_lhs = lhs_model.get_complementary_first_order_loss_function_value(x, nb_samples)

print("CL(x) using SRS:", cl_srs)
print("CL(x) using LHS:", cl_lhs)

Use SRS for a straightforward baseline and LHS when you want lower Monte Carlo variance for the same sample count.

2. Scalar-product first-order loss with multivariate normal demand

import numpy as np

from folf import FirstOrderLossFunctionScalarProductMVN

model = FirstOrderLossFunctionScalarProductMVN(
	mean=np.array([10.0, 15.0, 20.0]),
	covariance=np.array(
		[
			[4.0, 1.2, 0.8],
			[1.2, 9.0, 2.0],
			[0.8, 2.0, 16.0],
		]
	),
	independent_demand=False,
)

weights = np.array([0.5, 0.3, 0.2])
y = 14.0

cl = model.get_complementary_first_order_loss_function_value(y, weights)
l = model.get_first_order_loss_function_value(y, weights)

print("CL(y):", cl)
print("L(y):", l)

3. Choose piecewise linearization parameters

If you are embedding first-order loss terms in an optimization model (for example MILP or MIP), you typically replace nonlinear loss expressions with a piecewise linear approximation. LinearisationFactory.choose_linearisation_parameters helps pick:

  • w_segments: how many loss-function segments to use
  • q: how many variance/sqrt partitions to use

for a requested approximation tolerance epsilon, variance bound vmax, and cost coefficient c.

from folf import LinearisationFactory

epsilon = 0.5
vmax = 4.0
c = 10.0

w_segments, q = LinearisationFactory.choose_linearisation_parameters(epsilon, vmax, c)
print("segments:", w_segments)
print("q:", q)

Typical Workflow

  1. Model your demand distribution(s) with SciPy distributions or a normal mean/covariance pair.
  2. Compute CL(x) or L(x) either empirically (sampling) or from the MVN closed-form helper.
  3. If building optimization models, use the Jensen partitioners or linearization factory to derive approximation parameters.

Public API At A Glance

  • FirstOrderLossFunction
  • FirstOrderLossFunctionScalarProduct
  • FirstOrderLossFunctionScalarProductMVN
  • JensenUniformPartitioner
  • JensenMinimaxPartitioner
  • PiecewiseStandardNormalFirstOrderLossFunction
  • LinearisationFactory

Quality Checks

./venv/bin/python -m pytest -q
./venv/bin/python -m ruff check .
./venv/bin/python -m mypy src/folf

Release Metadata

Package Layout

  • src/folf: Main library package
  • src/folf/utilities: Utility modules
  • tests: Basic smoke and behavior tests

Release files for folf 1.0.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for folf 1.0.3
File Size Uploaded
folf-1.0.3.tar.gz 60.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for folf 1.0.3
File Interpreter ABI Platform
folf-1.0.3-py3-none-any.whl Python 3 none any Details

Total release size: 83.3 kB

Release files / folf-1.0.3.tar.gz

Download URL folf-1.0.3.tar.gz
Size 60.5 kB
Tags Source
SHA-256 checksum
How to use checksums
a1c61daa757e70581159af01c361e3e602ae9938caf0f94351e693fe8e7bdab8
BLAKE2b-256 checksum
How to use checksums
5d86d96d4bd7a948ec6238863739ec315bcebdb1cab7202bfda69ddf7611c20a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.12

Release files / folf-1.0.3-py3-none-any.whl

Download URL folf-1.0.3-py3-none-any.whl
Size 22.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
83b380cbe9345b9af1e9af87d5db4ed42434cd283d82b29468e6eeecde4d6b82
BLAKE2b-256 checksum
How to use checksums
15a85ce538f13ee89743c1a9dad09d2c5ad883ab0e579fa1faf8456c9f1c89f7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.12

Release history Release notifications | RSS feed

This release

1.0.3 This release

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page