Data Generators¶
pyepo.data includes synthetic data generators for four optimization problems: shortest path, multi-dimensional knapsack, traveling salesperson, and portfolio optimization.
Each generator produces feature-cost pairs \((\mathbf{x}, \mathbf{c})\). The feature vector \(\mathbf{x}_i \in \mathbb{R}^p\) follows a standard multivariate Gaussian distribution \(\mathcal{N}(0, \mathbf{I})\), and the cost \(\mathbf{c}_i \in \mathbb{R}^d\) is computed from a polynomial function \(f(\mathbf{x}_i)\) scaled by a multiplicative noise factor \(\boldsymbol{\epsilon}_i \sim U(1-\bar{\epsilon}, 1+\bar{\epsilon})\).
Common parameters across the generators:
num_data (\(n\)): number of data samples
num_features (\(p\)): feature dimension
deg (\(deg\)): polynomial degree of the mapping \(f(\mathbf{x}_i)\)
noise_width (\(\bar{\epsilon}\)): noise half-width for shortest path, knapsack, and TSP. Portfolio uses
noise_levelinstead; see below.seed: random seed for reproducibility
Shortest Path¶
A random matrix \(\mathcal{B} \in \mathbb{R}^{d \times p}\) with Bernoulli(0.5) entries maps the feature vector to the cost coefficients: \(c_i^j = \tfrac{1}{{3.5}^{deg}} \big[\big(\tfrac{1}{\sqrt{p}}(\mathcal{B} \mathbf{x}_i)_j + 3\big)^{deg} + 1\big] \cdot \epsilon_i^j\).
- pyepo.data.shortestpath.genData(num_data: int, num_features: int, grid: tuple[int, int], deg: int = 1, noise_width: float = 0, seed: int = 135) tuple[ndarray, ndarray]
Generate synthetic feature-cost pairs for the shortest path problem.
Features are sampled from a standard multivariate Gaussian \(\mathcal{N}(0, \mathbf{I})\). A random Bernoulli(0.5) matrix \(\mathcal{B}\) maps each feature vector into the edge-cost coefficients via a polynomial of degree
deg, scaled by multiplicative uniform noise of half-widthnoise_width.- Parameters:
num_data – number of data points
num_features – dimension of features
grid – size of grid network
deg – polynomial degree of the feature-to-cost mapping
noise_width – half-width of the multiplicative uniform noise
seed – random seed (default 135 for reproducibility)
- Returns:
data features (np.ndarray), costs (np.ndarray)
- Return type:
import pyepo
num_data = 1000 # number of samples
num_feat = 5 # number of features
grid = (5,5) # grid size
x, c = pyepo.data.shortestpath.genData(num_data, num_feat, grid, deg=4, noise_width=0, seed=135)
Knapsack¶
Only the cost coefficients are uncertain; item weights are fixed. Let \(m\) be the number of items and \(k\) the number of resource dimensions. The weights \(\mathcal{W} \in \mathbb{R}^{k \times m}\) are drawn uniformly from the half-open range \([3, 8)\) to two decimal places. The cost coefficients are \(c_i^j = \big\lceil \tfrac{5}{{3.5}^{deg}} \big[\big(\tfrac{1}{\sqrt{p}}(\mathcal{B} \mathbf{x}_i)_j + 3\big)^{deg} + 1\big] \cdot \epsilon_i^j \big\rceil\).
- pyepo.data.knapsack.genData(num_data: int, num_features: int, num_items: int, dim: int = 1, deg: int = 1, noise_width: float = 0, seed: int = 135) tuple[ndarray, ndarray, ndarray]
Generate synthetic feature-cost pairs for the multi-dimensional knapsack.
Item weights are fixed across instances; only the value (cost) of each item depends on features. Features are sampled from a standard Gaussian \(\mathcal{N}(0, \mathbf{I})\), mapped through a random Bernoulli(0.5) matrix \(\mathcal{B}\) and a polynomial of degree
deg, then scaled by multiplicative uniform noise of half-widthnoise_widthand rounded up to the nearest integer.- Parameters:
num_data – number of data points
num_features – dimension of features
num_items – number of items
dim – dimension of multi-dimensional knapsack
deg – polynomial degree of the feature-to-cost mapping
noise_width – half-width of the multiplicative uniform noise
seed – random state seed (default 135 for reproducibility)
- Returns:
weights of items (np.ndarray), data features (np.ndarray), costs (np.ndarray)
- Return type:
import pyepo
num_data = 1000 # number of samples
num_feat = 5 # number of features
num_item = 32 # number of items
dim = 3 # dimension of knapsack
weights, x, c = pyepo.data.knapsack.genData(num_data, num_feat, num_item, dim, deg=4, noise_width=0, seed=135)
Traveling Salesperson¶
The distance matrix has two components: a Euclidean distance term and a feature-encoded term. Coordinates are drawn from a mixture of a Gaussian distribution \(\mathcal{N}(0, \mathbf{I})\) and a uniform distribution \(U(-2, 2)\). The feature-encoded component is \(\tfrac{1}{{3}^{deg - 1}} \big(\tfrac{1}{\sqrt{p}} (\mathcal{B} \mathbf{x}_i)_j + 3\big)^{deg} \cdot \boldsymbol{\epsilon}_i\), where the elements of \(\mathcal{B}\) are products of Bernoulli(0.5) and uniform \(U(-2, 2)\) samples.
- pyepo.data.tsp.genData(num_data: int, num_features: int, num_nodes: int, deg: int = 1, noise_width: float = 0, seed: int = 135) tuple[ndarray, ndarray]
Generate synthetic feature-cost pairs for the traveling salesperson problem.
Edge costs combine a Euclidean component (node coordinates drawn from a mixture of a Gaussian \(\mathcal{N}(0, \mathbf{I})\) and a uniform \(\mathbf{U}(-2, 2)\) distribution) with a feature-encoded component obtained by mapping the standard-Gaussian feature vector through a random Bernoulli \(\times\) uniform matrix \(\mathcal{B}\) and a polynomial of degree
deg, scaled by multiplicative noise of half-widthnoise_width.- Parameters:
num_data – number of data points
num_features – dimension of features
num_nodes – number of nodes
deg – polynomial degree of the feature-to-cost mapping
noise_width – half-width of the multiplicative uniform noise
seed – random seed (default 135 for reproducibility)
- Returns:
data features (np.ndarray), costs (np.ndarray)
- Return type:
import pyepo
num_data = 1000 # number of samples
num_feat = 5 # number of features
num_node = 20 # number of nodes
x, c = pyepo.data.tsp.genData(num_data, num_feat, num_node, deg=4, noise_width=0, seed=135)
Portfolio¶
Let \(\bar{r}_{ij} = \big(\tfrac{0.05}{\sqrt{p}}(\mathcal{B} \mathbf{x}_i)_j + {0.1}^{\frac{1}{deg}}\big)^{deg}\). The expected return is \(\mathbf{r}_i = \bar{\mathbf{r}}_i + \mathbf{L} \mathbf{f} + 0.01 \tau \boldsymbol{\epsilon}\), and the covariance matrix is \(\mathbf{\Sigma} = \mathbf{L} \mathbf{L}^{\intercal} + (0.01 \tau)^2 \mathbf{I}\), where \(\mathcal{B}\) has Bernoulli(0.5) entries, \(\mathbf{L} \sim U(-0.0025\tau, 0.0025\tau)\), and \(\mathbf{f}, \boldsymbol{\epsilon} \sim \mathcal{N}(0, \mathbf{I})\).
Unlike the other generators, portfolio noise is controlled by noise_level (\(\tau\)), which scales both the factor loadings \(\mathbf{L}\) and the residual noise. noise_width does not apply here.
- pyepo.data.portfolio.genData(num_data: int, num_features: int, num_assets: int, deg: int = 1, noise_level: float = 1, seed: int = 135) tuple[ndarray, ndarray, ndarray]
Generate synthetic feature-cost pairs for portfolio optimization.
Returns the expected returns \(\mathbf{r}\) (the per-instance cost vectors) and a single shared covariance matrix \(\mathbf{\Sigma}\) used in the risk constraint of the predefined portfolio model. The mean returns follow a factor-model structure \(\mathbf{r}_i = \bar{\mathbf{r}}_i + \mathbf{L}\mathbf{f} + 0.01 \tau \boldsymbol{\epsilon}\), where the factor loadings \(\mathbf{L}\) and residual noise are both scaled by
noise_level(\(\tau\)). Unlike the other generators inpyepo.data, portfolio noise is controlled bynoise_levelrather thannoise_width.- Parameters:
num_data – number of data points
num_features – dimension of features
num_assets – number of assets
deg – polynomial degree of the feature-to-return mapping
noise_level – scales factor loadings L and residual noise (tau)
seed – random seed (default 135 for reproducibility)
- Returns:
covariance matrix (np.ndarray), data features (np.ndarray), mean returns (np.ndarray)
- Return type:
import pyepo
num_data = 1000 # number of samples
num_feat = 4 # number of features
num_assets = 50 # number of assets
cov, x, r = pyepo.data.portfolio.genData(num_data, num_feat, num_assets, deg=4, noise_level=1, seed=135)