Advanced / supplementary — beyond the textbook treatment
Manuel D. Rossetti, PhD P.E.
Learning Objectives
To be able to describe the integer-ordered simulation optimization problem and why it is challenging.
To be able to explain the three-level algorithmic structure of R-SPLINE: the retrospective framework, SPLINE, and SPLI/NE.
To be able to describe how piecewise-linear interpolation creates a continuous relaxation of a discrete objective function.
To be able to trace through the simplex construction and gradient estimation steps of the PLI algorithm.
To be able to map each algorithm in the paper (Algorithms 1–4) to its corresponding function in the KSL RSplineSolver implementation.
To be able to identify and interpret the key tuning parameters of the KSL R-SPLINE solver.
To be able to state the convergence guarantees of R-SPLINE and the conditions under which they hold.
Part 1: Motivation and Problem Setting
Integer-Ordered Simulation Optimization
The General SO Problem:
\[\min_{x \in X \subseteq \mathbb{Z}^d} \; g(x)\]
where:
\(g : x \mapsto \mathbb{R}\) is a black-box objective, observable only via a stochastic simulation oracle.
At any \(x\), only a noisy estimate \(\hat{g}_m(x)\) is available from \(m\) replications.
As \(m \to \infty\): \(\hat{g}_m(x) \to g(x)\) with probability 1.
The decision variables \(x = (x_1, x_2, \ldots, x_d)\) are integer-valued.
Practical examples: inventory reorder points and quantities, number of machines/servers, staffing levels, buffer sizes.
Why Is This Hard?
Three compounding challenges:
Stochastic noise — we never observe \(g(x)\) exactly; only a noisy estimate \(\hat{g}_m(x)\).
No analytical gradient — \(g\) is implicit in a simulation; derivatives are not available in closed form.
Integer domain — continuous gradient methods cannot be applied directly; combinatorial search is expensive.
The key insight of R-SPLINE: construct a continuous relaxation of \(\hat{g}_m(\cdot)\) over the integer lattice using piecewise-linear interpolation, apply gradient search on that relaxation, then snap back to integers.
Classification of SO Algorithms
Finite (General)
Integer-Ordered (Finite)
Integer-Ordered (Infinite)
Local
N/A
Coordinate Search, COMPASS, DSA
← R-SPLINE fits here
Global
R&S Methods
Stochastic Ruler, Nested Partition, …
Modified Stochastic Ruler, …
R-SPLINE targets local optima on integer-ordered, potentially infinite feasible spaces.
Of 50 benchmark SO problems in the literature, 25 fall in exactly this category (Wang et al. 2013).
R-SPLINE = Retrospective Search with Piecewise-Linear Interpolation and Neighborhood Enumeration
Letter(s)
Meaning
R
Retrospective — solve a sequence of sample-path problems with growing \(m_k\)
SPL
Search with Piecewise-Linear Interpolation — gradient search on a continuous relaxation
I
Interpolation — the PLI routine that extends \(\hat{g}_{m_k}(\cdot)\) to \(\mathbb{R}^d\)
NE
Neighborhood Enumeration — a discrete local-optimality check
Part 2: Local Optimality on Integer Lattices
Defining Neighborhoods
Definition (Neighborhood): The neighborhood \(N(\mathbf{0})\) of the \(d\)-dimensional origin is any subset of \(\mathbb{Z}^d\) containing the origin. The neighborhood of any \(x \in \mathbb{Z}^d\) is: \[N(x) = \{y : (y - x) \in N(\mathbf{0})\}\]
Two important special cases used in R-SPLINE:
\(N_1(x)\): the \(2d\) integer points exactly one unit away from \(x\) (von Neumann neighborhood). \[N_1(x) = \{x \pm e_i : i = 1, \ldots, d\}\]
\(N_2(x)\): all integer points within 2 units of \(x\).
R-SPLINE targets \(N_1\)-local minima — the smallest computationally tractable neighborhood.
N1-Local Minimum
Definition: A point \(x^* \in = X\) is an \(N_1\)-local minimizer of \(g\) if: \[g(x) \geq g(x^*) \quad \forall x \in N_1(x^*) \cap X\]
That is, \(x^*\) is no worse than any of its \(2d\) immediate neighbors.
Key properties:
The set of \(N_1\)-local minima \(M^*(N_1)\) contains all global minima.
Larger neighborhoods \(\Rightarrow\) fewer local minima (higher quality but costlier to verify).
R-SPLINE uses \(N_1\) because NE requires evaluating all \(2d\) neighbors — manageable even in high \(d\).
SPLI compensates for the small neighborhood by allowing large, off-axis moves.
In KSL: The Von Neumann Neighborhood
The KSL implementation uses a vonNeumannNeighborhoodFinder by default, which directly realizes the \(N_1\) neighborhood:
The neighborhood finder returns the set of all input maps one unit away in each coordinate direction.
Only input-feasible neighbors (satisfying bounds and deterministic constraints) are retained.
Users can substitute a different neighborhood finder if a larger structure is preferred.
Part 3: The Three-Level Algorithm Structure
R-SPLINE Architecture Overview
R-SPLINE (outer loop — Algorithm 1)
│
│ for k = 1, 2, 3, ...
│ solve sample-path problem P_k using SPLINE
│ warm-start next iteration with X*_k
│
└─► SPLINE (Algorithm 2)
│
│ repeat until N1-local optimum found or budget b_k exhausted:
│ SPLI → NE → SPLI → NE → ...
│
├─► SPLI (Algorithm 4) — gradient line search on continuous relaxation
│ └─► PLI (Algorithm 3) — piecewise-linear interpolation + gradient
│ └─► PERTURB — shifts integer point into a simplex interior
│
└─► NE — enumerate all N1 neighbors, pick the best
Each level has a distinct role. Together they combine the efficiency of gradient search with the correctness guarantee of discrete local-optimality checking.
The Retrospective Framework (Algorithm 1)
Core idea: solve a sequence of sample-path problems\(P_k\), each with a larger sample size \(m_k\):
\[(P_k): \text{ Find } X^*_k \in X \text{ such that } \hat{g}_{m_k}(x) \geq \hat{g}_{m_k}(X^*_k) \quad \forall x \in N_1(X^*_k)\]
Algorithm 1 pseudocode:
Set X*_0 = x0 (initial solution)
for k = 1, 2, 3, ...
X*_k = SPLINE(X*_{k-1}, m_k, b_k)
end for
Three distinguishing features:
Independent sample paths — different random numbers used each iteration \(k\).
Increasing sample sizes — \(m_k \uparrow \infty\), so each \(P_k\) is a better approximation of \(g\).
Warm starts — \(X^*_{k-1}\) seeds iteration \(k\), making later iterations fast.
Retrospective Framework: Why It Works
Early iterations (\(k\) small, \(m_k\) small):
Computation per point is cheap.
SPLINE explores broadly; many oracle calls acceptable because each is inexpensive.
Purpose: quickly find a good neighborhood of the true local minimum.
Later iterations (\(k\) large, \(m_k\) large):
Warm start \(X^*_{k-1}\) is already near the true local minimum.
SPLINE needs few oracle calls (sample path agrees with \(g\) closely).
Purpose: confirm the local minimum with high statistical confidence.
Efficiency gain: most of the computation budget is spent in early iterations where evaluations are cheap.
Mapping to KSL: mainIteration()
Algorithm 1’s loop body maps directly to mainIteration() in RSplineSolver:
overridefunmainIteration(){// Call SPLINE for the next solution using// current sample size (m_k) and SPLINE call limit (b_k).valsplineSolution= spline( currentSolution, rSPLINESampleSize,// this is m_k splineCallLimit // this is b_k) currentSolution = splineSolution solutionChecker.captureSolution(currentSolution)}
rSPLINESampleSize returns \(m_k\) from the FixedGrowthRateReplicationSchedule.
The schedule satisfies the theoretical requirement that \(m_k \uparrow \infty\) faster than logarithmically, ensuring convergence. The growth rate is very mild — only 10% more replications per iteration.
Part 4: SPLINE — Solving Each Sample-Path Problem
SPLINE: The Sample-Path Solver (Algorithm 2)
For a fixed \(k\), SPLINE finds an \(N_1\)-local minimum of the sample-path objective \(\hat{g}_{m_k}(\cdot)\):
Inputs: initial solution X_new, sample size m_k, oracle call budget b_k
Set oracle call counter n = 0
repeat
[n', X_old] = SPLI(X_new, m_k) // gradient line search
if g_hat(X_old) > g_hat(X_new):
X_old = X_new // SPLI cannot cause harm
[n'', X_new] = NE(X_old, m_k) // neighborhood check
n = n + n' + n''
until X_new == X_old OR n > b_k
Termination: SPLINE stops when NE confirms \(X_{old}\) is \(N_1\)-locally optimal (no neighbor is better), or the call budget \(b_k\) is exhausted.
SPLINE in KSL: spline() Function
privatefunspline(initSolution:Solution,sampleSize:Int,splineCallLimit:Int):Solution{varnewSolution=/* re-evaluate at m_k if needed */valstartingSolution= newSolutionfor(i in1..splineCallLimit){valspliResults= searchPiecewiseLinearInterpolation(newSolution, sampleSize)// SPLI cannot cause harm: keep current if SPLI didn't improvevalneStartingSolution=if(compare(spliResults.solution, newSolution)<=0) spliResults.solution else newSolutionvalneSearchResults= neighborhoodSearch(neStartingSolution, sampleSize) newSolution = neSearchResults.solution// If NE confirmed local optimality: breakif(neStartingSolution == neSearchResults.solution)break}// Return best feasible solution found; fall back to startingSolution if no improvementreturnif(compare(startingSolution, newSolution)<0) startingSolutionelseif(newSolution.isInputFeasible()) newSolutionelse startingSolution}
Key implementation notes:
The loop bound splineCallLimit corresponds to \(b_k\) in the paper. Safety check: if SPLINE returns an infeasible solution, the starting solution is returned. The re-evaluation step ensures the initial solution uses the current \(m_k\) sample size.
Neighborhood Enumeration: NE
NE is the simplest component — it exhaustively evaluates all \(N_1\) neighbors:
Evaluate all feasible x in N1(X_old) using m_k replications each.
Case 1: Unique best neighbor x better than X_old → return x.
Case 2: X_old tied for best → return X_old (local optimum confirmed).
Case 3: Multiple neighbors tied for best and better → return any one.
NE is the local optimality verifier — SPLI does the exploration, NE does the confirmation.
Part 5: Piecewise-Linear Interpolation (PLI)
Why Interpolate?
The objective \(\hat{g}_{m_k}(\cdot)\) is only defined on integer points \(X \subseteq \mathbb{Z}^d\).
To perform a gradient-based line search, we need a continuous extension\(g_{m_k}(\cdot) : \mathbb{R}^d \to \mathbb{R}\) that:
Agrees with \(\hat{g}_{m_k}(\cdot)\) at every integer point.
Is continuous everywhere (so the gradient is well-defined almost everywhere).
Is cheap to compute (only \(d+1\) oracle calls per simplex evaluation).
Has local solutions that encompass the \(N_1\)-optimal integer solutions.
The chosen method: simplicial piecewise-linear interpolation. Every non-integer point \(x \in \mathbb{R}^d \setminus \mathbb{Z}^d\) lies inside a simplex formed by \(d+1\) nearby integer vertices.
The Simplex Construction
Step 1: Find the floor vertex \(x^0\): \[x^0_i = \lfloor x_i \rfloor, \quad i = 1, \ldots, d\]
Step 3: Sort the fractional parts in descending order. Let \(p(1), p(2), \ldots, p(d)\) be the permutation such that: \[1 = z_{p(0)} > z_{p(1)} \geq z_{p(2)} \geq \cdots \geq z_{p(d)} \geq z_{p(d+1)} = 0\]
Step 4: Build the remaining \(d\) vertices by sequentially adding unit vectors: \[x^i = x^{i-1} + e_{p(i)}, \quad i = 1, 2, \ldots, d\]
Interpretation: Each component \(\hat{\gamma}_{p(i)}\) measures the change in the estimated objective when moving one unit in the \(p(i)\)-th coordinate direction, at the current simplex location.
Properties of the gradient estimate:
Available only when all \(d+1\) vertices are feasible.
If any vertex is infeasible, gradient computation is skipped (SPLI falls back gracefully).
Uses common random numbers across all simplex vertices → reduces variance of comparisons.
CRN note: The requestEvaluationsWithCRN() call synchronizes random number streams across all simplex vertices — directly implementing the paper’s common random numbers requirement.
The PERTURB Step
Why perturb? The PLI algorithm requires a non-integer input point \(x_1 \in \mathbb{R}^d \setminus \mathbb{Z}^d\) to define a simplex. The current best solution \(X_{best}\) is always an integer point, so it must be randomly displaced.
The PERTURB function adds a small uniform random perturbation to each coordinate:
funaddRandomPerturbation(point:DoubleArray,perturbationFactor:Double,rnStream:RNStreamIfc):DoubleArray{for(i in point.indices){ point[i]= point[i]+ rnStream.rUniform(-perturbationFactor, perturbationFactor)}return point}
perturbationFactor (default 0.15) must be in \((0, 1)\) to keep the perturbed point strictly within the surrounding hypercube.
Perturbation randomizes which simplex \(X_{best}\) is assigned to, providing variation in the gradient direction across SPLI iterations.
Part 6: SPLI — The Gradient Line Search
SPLI Overview (Algorithm 4)
SPLI performs a gradient-based line search on the continuous relaxation \(g_{m_k}(\cdot)\). It returns \(X_{best}\): the best integer solution found.
Set X_best = x_0, n' = 0
loop (new line search with new gradient estimate):
x_1 = PERTURB(X_best)
Call PLI(x_1, m_k) → get g_mk(x_1) and gradient γ̂
If ||γ̂|| = 0 or undefined: STOP (no direction available)
i = 0; x_0 = X_best
loop (line search steps with doubling step size):
i++
s = c^(i-1) * s_0; x_1 = x_0 - s * (γ̂ / ||γ̂||)
Round x_1 to nearest integer.
If x_1 infeasible: STOP
Simulate at x_1; update n'
If i ≤ 2 and no improvement: STOP (wrong direction)
If i > 2 and no improvement: BREAK (continue outer loop)
go back to top (new gradient estimate)
SPLI: Step Size Doubling
The line search uses an exponentially increasing step size: \[s_i = s_0 \cdot c^{i-1}, \quad s_0 = 2.0, \; c = 2.0\]
Iteration \(i\)
Step size \(s_i\)
1
\(2.0\)
2
\(4.0\)
3
\(8.0\)
4
\(16.0\)
5
\(32.0\)
\(s_0 = 2.0\) ensures the first step moves outside the immediate hypercube (avoids returning to \(x^0\) trivially).
Doubling allows large moves — directly compensating for the small \(N_1\) neighborhood.
Movement direction: negative gradient (steepest descent): \(x_1 = x_0 - s \cdot \hat{\gamma} / \|\hat{\gamma}\|\)
SPLI: Four Stopping Conditions
SPLI halts a line search early if any of the following occur:
Condition
Action
\(\|\hat{\gamma}\|\) undefined or zero
No gradient direction; return \(X_{best}\)
\(n' > b_k\)
Budget exhausted; return \(X_{best}\)
\(x_1\) is infeasible
Boundary hit; return \(X_{best}\)
\(i \leq 2\) and no improvement
Wrong direction; return \(X_{best}\)
After step \(i > 2\), a non-improving step breaks the inner loop to start a new gradient estimate rather than stopping entirely — allowing SPLI to recover and search in a different direction.
The KSL implementation adds explicit iteration limits on inner loops to prevent runaway computation in edge cases, while preserving the algorithm’s essential structure.
Part 7: Convergence Theory
Convergence Setup
Two assumptions underpin R-SPLINE’s convergence guarantees:
Assumption 1 (Bounded level sets): For every \(x \in X\), there exists \(\delta > 0\) such that the level set \[S(x, \delta) = \{x' \in X : g(x') \leq g(x) + \delta\}\] is finite. This prevents the iterates from “escaping to infinity.”
Assumption 2 (Fast enough probability decay): For \(x \in X\) and \(y \notin S(x,\delta)\), there exists a summable sequence \(\{q_k\}\) such that \(P\{y \in S_k(x)\} \leq q_k\) and \(\sum_{k=1}^\infty q_k < \infty\).
This is a Borel-Cantelli condition ensuring that bad sample-path outcomes become rare fast enough.
When Do the Assumptions Hold?
Lemma 5.1 (Large Deviations): If \(\{\hat{g}_{m_k}(x) - g(x)\}\) satisfies a large-deviation principle with a non-degenerate rate function \(I_x(s)\), and the sample sizes grow faster than logarithmically: \[\limsup_{k \to \infty} m_k^{-1} (\log k)^{1+\varepsilon} = 0 \text{ for some } \varepsilon > 0\] then Assumption 2 holds.
Practical implication: The 10% growth schedule \(m_{k+1} = \lceil 1.1 m_k \rceil\) easily satisfies this (geometric growth \(\gg\) logarithmic). Even \(m_k = (\log k)^2\) is sufficient.
Lemma 5.2 (CLT-based): If a CLT holds for \(\hat{g}_{m_k}\) with uniformly bounded variance, Assumption 2 holds for sample sizes growing faster than quadratically in \(k\).
Main Convergence Results
Theorem 5.4 (Almost-sure convergence):
Under Assumptions 1 and 2, for any starting point \(x_0\): \[P\{X^*_k \notin M^*(N_1) \text{ infinitely often}\} = 0\]
That is, after a finite random number of iterations, all subsequent iterates are true \(N_1\)-local minima, with probability one.
Theorem 5.5 (Exponential convergence rate):
If \(X\) is finite and \(\{\hat{g}_{m_k}(x) - g(x)\}\) satisfies a large-deviation principle:
\(P\{M^*_k(N_1) \neq M^*(N_1)\} = O(\exp\{-\beta m_k\})\) for some \(\beta > 0\).
If \(m_k\) grows at least linearly: \(P\{X^*_k \notin M^*(N_1)\} = O(\exp\{-\beta k\})\).
The probability of returning a false local minimum decays exponentially in the sample size.
Interpretation of Convergence
Result
Practical Meaning
Theorem 5.4
Given enough iterations, R-SPLINE will eventually “lock onto” a true local minimum and stay there.
Theorem 5.5(i)
As we use more replications per evaluation, the chance of a wrong answer shrinks exponentially.
Theorem 5.5(ii)
With linearly growing sample sizes, the error probability shrinks exponentially in the iteration count.
Important caveat: R-SPLINE converges to a local minimum — not necessarily the global minimum. When multiple local minima exist with differing objective values, ISC/ISC-AHA (with their global Phase I search) may return better-quality solutions, at the cost of more oracle calls.
Part 8: Key Parameters and Their Roles
Sample Size Schedule Parameters
These parameters control the \(m_k\) sequence — the most theoretically important parameters:
KSL Parameter
Paper Symbol
Default
Role
initialNumReps
\(m_1\)
8
Starting sample size
sampleSizeGrowthRate
growth of \(m_k\)
0.10
10% increase per iteration
maxNumReplications
—
library default
Cap to prevent runaway growth
Effect: Larger \(m_1\) gives a more reliable starting point but delays the warm-start advantage. Higher growth rate converges faster theoretically but spends more budget per iteration.
SPLINE Call Budget Parameters
These parameters control \(b_k\) — the per-iteration budget for SPLINE iterations:
A growing \(b_k\) is needed for convergence when \(X\) is unbounded — SPLINE must be allowed to search longer as iterations proceed.
SPLI Search Parameters
These control the inner gradient search within each SPLINE iteration:
KSL Parameter
Paper Default
KSL Default
Role
initialLineSearchStepSize (\(s_0\))
2.0
2.0
Starting step size for line search
lineSearchStepSizeMultiplier (\(c\))
2.0
2.0
Step size doubling factor
lineSearchIterMax
unlimited
10
Maximum line search steps per gradient
spliMaxIterations
unlimited
5
Maximum gradient estimates per SPLINE call
perturbation
small
0.15
Perturbation factor for PERTURB step
Advice: The defaults are well-tested. Increase spliMaxIterations or lineSearchIterMax for high-dimensional problems where a single gradient estimate may not provide enough search direction.
Stopping and Outer Loop Parameters
KSL Parameter
Default
Role
maxIterations
library default
Hard cap on outer R-SPLINE iterations (= \(k_{max}\))
defaultNoImproveThresholdForRSPLINE
10
Stop if last 10 solutions are statistically equal
solutionEqualityChecker
InputsAndConfidenceIntervalEquality
Defines “equal” solutions for stopping
KSL-specific stopping criterion: The paper does not specify when to stop the outer loop. KSL adds a practical stopping rule: if the last \(N\) consecutive solutions are statistically indistinguishable (same inputs AND no significant difference in penalized objective function via confidence interval test), the algorithm terminates early.
Parameter Summary Table
Category
Parameter
Default
Increase when…
Sample size
initialNumReps
8
Noise is high
Sample size
sampleSizeGrowthRate
0.10
Fast convergence is needed
SPLINE budget
initialMaxSplineCallLimit
10
Problem is high-dimensional
SPLINE budget
splineCallGrowthRate
0.10
Search space is large
SPLI
spliMaxIterations
5
\(d\) is large
SPLI
lineSearchIterMax
10
Objective surface is complex
SPLI
perturbation
0.15
Getting stuck at boundary
SPLI
initialLineSearchStepSize
2.0
Decision variables have large ranges
Stopping
maxIterations
library
Budget allows
Stopping
noImproveThreshold
10
More robustness wanted
Part 9: Using RSplineSolver in KSL
Constructor and Setup
RSplineSolver requires an integer-ordered problem definition. Two constructor forms:
Requirement:problemDefinition.isIntegerOrdered must be true — enforced at construction time.
Common Random Numbers in KSL
The paper emphasizes that all evaluations within iteration \(k\) use the same random seed \(\xi_k\), making comparisons between points more reliable.
In KSL, this is handled automatically:
requestEvaluationsWithCRN() is called for simplex vertex evaluation inside piecewiseLinearInterpolation().
The rnStream property provides a single random number stream for perturbation.
The evaluator infrastructure manages CRN alignment across oracle calls within an iteration.
Effect: Common random numbers create positive correlation between \(\hat{g}_{m_k}(x_1)\) and \(\hat{g}_{m_k}(x_2)\) for different \(x_1, x_2\), which increases the probability that comparisons correctly identify the better point.
R-SPLINE solves integer-ordered local SO problems by alternating a continuous gradient search (SPLI) with a discrete local-optimality check (NE), inside a retrospective framework.
Piecewise-linear interpolation creates a continuous relaxation of the noisy discrete objective using only \(d+1\) function evaluations per simplex, providing gradient directions for free.
Convergence is almost sure to the set of \(N_1\)-local minima, and the probability of error decays exponentially in the sample size when the feasible region is finite.
The 10% sample size growth rule (\(m_{k+1} = \lceil 1.1 m_k \rceil\)) satisfies the convergence conditions easily. Most computation happens early when evaluations are cheap.
The KSL implementation follows the paper faithfully but adds practical limits (spliMaxIterations, lineSearchIterMax) and a confidence-interval-based stopping criterion not in the original paper.
R-SPLINE outperforms ISC and ISC-AHA in terms of oracle calls to near-optimality, especially as dimension grows, due to gradient-guided search and negligible overhead.
References
Wang, H., Pasupathy, R., and Schmeiser, B. W. (2013). Integer-ordered simulation optimization using R-SPLINE: Retrospective Search with Piecewise-Linear Interpolation and Neighborhood Enumeration. ACM Transactions on Modeling and Computer Simulation, 23(3), Article 17.
Hong, J. and Nelson, B. (2006). Discrete optimization via simulation using COMPASS. Operations Research, 54(1), 115–129.
Xu, J., Hong, L. J., and Nelson, B. L. (2010). Industrial strength COMPASS: A comprehensive algorithm and software for optimization via simulation. ACM Trans. Model. Comput. Simul., 20, Article 19.
Pasupathy, R. (2010). On choosing parameters in retrospective-approximation algorithms for stochastic root finding and simulation optimization. Operations Research, 58, 889–901.