Skip to main content

folf

Python library implementation of first-order loss function tooling, mirroring the Java classes in java/folf and java/utilities.

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

Features

  • Empirical first-order and complementary first-order loss functions
  • Scalar-product variants, including multivariate normal closed-form approximation
  • Jensen partitioners (uniform and minimax)
  • Piecewise linearization helpers and linearization-parameter chooser
  • Probability sampling utilities (SRS and LHS)
  • Utility modules for SHA-256 and JSON serialization

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.

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 analogous to Java utilities
  • tests: Basic smoke and behavior tests

Changelog

Release notes follow Keep a Changelog. See CHANGELOG.md.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

folf-1.0.0.tar.gz (59.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

folf-1.0.0-py3-none-any.whl (22.2 kB view details)

Uploaded Python 3

File details

Details for the file folf-1.0.0.tar.gz.

File metadata

  • Download URL: folf-1.0.0.tar.gz
  • Upload date:
  • Size: 59.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.12

File hashes

Hashes for folf-1.0.0.tar.gz
Algorithm Hash digest
SHA256 12c663a8f5531eaf4dc41b826fe0198149432cbfb43743727957916e5febf206
MD5 d823b7ea240e274f31375b9a4f565fd8
BLAKE2b-256 07ce63a7bd694d5b5dd2af2cd79033d64be788cdf957f5700f44175214720866

See more details on using hashes here.

File details

Details for the file folf-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: folf-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 22.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.12

File hashes

Hashes for folf-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1332b846bd63fa3632efaccb5c59cbbe7b367244acce2145f6e7771e5e8327cc
MD5 df9834b87cc91f777cb1529dc3a43d56
BLAKE2b-256 bfd903125dc765cc58d3779dbb940cddfb5549d8d23bd54bfef7ad984c608942

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page