Tutorials › Group Sequential Methods and Sample Size Re-Estimation › Implementing Stopping Rules in Simulation Code

Software, Planning and Reporting · Tutorial 680 of 699

Implementing Stopping Rules in Simulation Code

Translate sequential stopping boundaries into a clear, auditable simulation algorithm and check its classifications on hypothetical trial paths.

Intermediate 12 min read

What You'll Learn

  • Define a first-crossing stopping rule using scheduled looks and efficacy and futility boundaries.
  • Separate the stopping look, stopping reason, and final trial outcome in simulation records.
  • Apply the rule to paths that stop early and paths that reach the maximum look.
  • Handle boundary checks, missing values, and terminal-look decisions consistently.
  • Check an implementation against hand-classified paths before running a simulation.

From a Boundary Specification to a Decision on Each Path

A simulated trial path may contain results at several planned interim looks. The stopping rule turns those sequential results into one operational record: whether the trial stops, at which look it stops, why it stops, and what final outcome label the simulation assigns. The essential implementation principle is first crossing: once a path meets a stopping condition, later results on that path cannot change its recorded decision.

This tutorial assumes that the look schedule, the statistic calculated at each look, and the efficacy and futility boundaries have already been specified. It focuses on translating those specifications into unambiguous logic. The boundary values below are hypothetical examples for illustrating code behavior; they do not establish a recommended design or operating characteristics.

Definition: Let \(K\) be the number of planned looks, indexed \(k=1,\ldots,K\). At look \(k\), let \(Z_k\) be the prespecified test statistic, \(u_k\) the efficacy boundary, and \(l_k\) the futility boundary. For a statistic where larger values favor the treatment, the path stops for efficacy if \(Z_k \ge u_k\), and stops for futility if \(Z_k \le l_k\). If neither condition holds, the path continues when another planned look remains.

The rule assumes that each boundary is paired with the correct look and statistic, that the statistic is oriented as specified (larger values favor the treatment here), and that the boundaries do not conflict. In the examples, \(l_k < u_k\) at every look, so a value cannot meet both conditions. A design using another direction, a different statistic, or a different stopping convention must encode that specification instead; the algorithm must not silently reinterpret it.

Specify the Recorded Decision Precisely

Three fields should be kept distinct. The stopping look is the index \(k\) where the path first stops, or \(K\) if it reaches the maximum look without an earlier stop. The stopping reason identifies efficacy, futility, or reaching the maximum look without crossing either boundary. The final trial outcome is the design’s final classification, such as efficacy success or no efficacy success. These are related, but they are not interchangeable: a path can stop for futility at look 2, while its final outcome is “no efficacy success.”

For a path with values \(Z_1,\ldots,Z_K\), define the first boundary-crossing look as the smallest \(k\) at which either stopping condition holds. If there is no such look, the path ends at \(K\). A path that crosses for efficacy is classified as an efficacy success. A path that crosses for futility is classified as no efficacy success under this rule. If neither boundary is crossed, the path completes the maximum look and is also classified as no efficacy success. This outcome label describes the simulated decision, not whether the treatment truly works.

$$ \tau = \begin{cases} \min\{k: Z_k \ge u_k \text{ or } Z_k \le l_k\}, & \text{if a boundary is crossed},\\ K, & \text{if no boundary is crossed}. \end{cases} $$

The stopping reason at \(\tau\) is efficacy if \(Z_\tau \ge u_\tau\), futility if \(Z_\tau \le l_\tau\), and maximum-look completion if neither condition holds. That last case applies only when no earlier look crossed a boundary. The word “completion” here means completion of the planned analysis schedule, not necessarily completion of every operational activity in a real trial.

A Direct Implementation Pattern

A transparent implementation initializes each path as active and then visits its planned looks in order. At each look, it evaluates the boundary conditions only for paths still active. When a condition is met, it records the decision and marks the path inactive. This prevents later values from overwriting the first stopping decision.

1
Initialize the path record.
Set the path as active. Leave the stopping look and reason unassigned, and reserve a final-outcome field. Check that the path contains one valid statistic for each planned look.
2
Evaluate looks in order.
For each active path at look \(k\), compare \(Z_k\) with the corresponding \(u_k\) and \(l_k\). Do not compare a statistic at look \(k\) with a boundary from another look.
3
Record the first crossing.
If \(Z_k \ge u_k\), record look \(k\), reason “efficacy,” and outcome “efficacy success.” Otherwise, if \(Z_k \le l_k\), record look \(k\), reason “futility,” and outcome “no efficacy success.” Mark the path inactive in either case.
4
Finalize paths still active after look \(K\).
Record stopping look \(K\), reason “maximum look,” and outcome “no efficacy success.” This assignment applies only to paths that did not already stop.

The “otherwise” in the futility check is deliberate. With \(l_k < u_k\), the conditions are mutually exclusive, but an explicit order makes the intended priority visible if a future specification changes. If boundaries overlap, or the specification gives simultaneous or competing rules, the design author must resolve that policy before coding; arbitrary if-statement order is not a statistical justification.

Before applying boundaries, validate the inputs. The number of statistic values must equal \(K\), the boundary arrays must also have \(K\) entries, and all values used in a comparison must be present and finite. A missing or invalid statistic is not evidence to continue. The simulation should flag the path as invalid or failed according to a stated data-handling policy rather than classifying it as “no crossing.”

Worked Example: Stopping for Efficacy at the Second Look

Suppose a hypothetical design has three looks, with \(u=(2.80, 2.20, 2.00)\) and \(l=(-0.50,-0.50,-0.50)\). Consider a generated path with \(Z_1=1.40\), \(Z_2=2.35\), and \(Z_3=2.60\). Assume the statistics are valid, use the specified direction, and correspond in order to these three looks.

At look 1, \(1.40 < 2.80\) and \(1.40 > -0.50\), so neither boundary is crossed. The path remains active. At look 2, \(2.35 \ge 2.20\), so the first crossing is for efficacy and \(\tau=2\). The result at look 3 is not evaluated for this path’s stopping decision, even though it is also above its efficacy boundary.

The record is stopping look 2, stopping reason “efficacy,” and final outcome “efficacy success.” A coding error that stores look 3 because it is the last observed value would violate the first-crossing rule.

Worked Example: Futility at the Final Planned Look

Use the same three-look boundaries. A second hypothetical path has \(Z_1=0.20\), \(Z_2=-0.10\), and \(Z_3=-0.62\). The values are finite, are in the correct look order, and are produced under the same statistic convention as the boundaries.

At looks 1 and 2, the statistic lies between the lower and upper boundaries, so the path continues. At look 3, \(-0.62 \le -0.50\), so the path stops for futility at \(\tau=3\). The stopping look is 3, the stopping reason is “futility,” and the final outcome is “no efficacy success.”

Reaching the final planned look does not automatically mean the reason is “maximum look.” The boundary is still evaluated at that look. “Maximum look” is the reason only if the path is still active after all boundary checks at look \(K\).

Why the First-Crossing Rule Is the Right Record

The first-crossing definition follows directly from the operational meaning of a sequential stopping rule. At each look \(k\), the decision depends on the information available at that look and the prespecified rule for that look. If a stop occurs there, the path is no longer eligible for a later decision. Thus, the recorded stopping look must be the smallest index satisfying a stopping condition, not the last index in the stored path.

The implementation can be understood inductively. Before look 1, every path is active. After evaluating look 1, each path either remains active or has its first decision recorded. Suppose this is true after look \(k-1\). At look \(k\), only paths that remained active are tested. A newly crossing path has not crossed at any earlier evaluated look, so \(k\) is its first crossing. Previously stopped paths are untouched. After look \(K\), any remaining active path has had no crossing at any planned look, so it is correctly assigned the maximum-look reason.

$$ \text{active after look } k \quad\Longleftrightarrow\quad Z_j < u_j \text{ and } Z_j > l_j \text{ for every evaluated } j \le k $$

The equivalence uses the assumption that all evaluated values are valid and that boundary comparisons are the stated inclusive comparisons for stopping. In particular, a value exactly equal to \(u_k\) stops for efficacy, and a value exactly equal to \(l_k\) stops for futility. Replacing either comparison with a strict comparison changes the specified rule at equality.

Worked Example: Classifying Several Paths and Checking the Output

Consider four hypothetical paths under the same boundaries. Each row lists statistics in order across the three planned looks. All entries are finite and correspond to the specified statistic and look schedule.

Path\(Z_1\)\(Z_2\)\(Z_3\)Expected stopping lookExpected reasonFinal outcome
A0.100.400.803Maximum lookNo efficacy success
B-0.600.301.101FutilityNo efficacy success
C2.903.103.201EfficacyEfficacy success
D0.002.10-0.703FutilityNo efficacy success

For path A, each value is below its efficacy boundary and above \(-0.50\), so it remains active through look 3 and is classified as maximum-look completion. Path B meets \(-0.60 \le -0.50\) at look 1, so later values cannot alter its futility decision. Path C meets \(2.90 \ge 2.80\) at look 1 and stops for efficacy immediately. Path D continues at looks 1 and 2 because \(0.00\) and \(2.10\) meet neither stopping condition; at look 3, \(-0.70 \le -0.50\), so it stops for futility.

A useful hand check is that the outcome “efficacy success” appears only for paths that cross an efficacy boundary first. A second check is that each stopping look agrees with the earliest crossing, not simply the last nonmissing statistic.

Diagnostics, Alternatives, and Limitations

Several simple diagnostics catch common implementation failures before results are summarized. Confirm that each path has exactly the expected number of statistics; that every boundary array has the same length; that the look index is paired correctly with each value; and that every stopped path has exactly one stopping reason and one final outcome. Also check that no path has a stopping look outside \(1,\ldots,K\), and that no path is both an efficacy success and a futility stop.

The main alternative to sequential, first-crossing evaluation is to classify paths from their final-look statistic alone. That approach may answer a different question, but it is not an implementation of a rule that can stop at interim looks: it ignores early crossings and can misclassify the stopping look and reason. Another tempting approach is to inspect every look and retain the last crossing. That also changes the rule, because it allows later results to overwrite a decision that should already have stopped the path.

A further distinction is between the rule encoded for the simulation and a protocol’s actual operational policy. For example, some designs describe futility stopping as nonbinding, meaning the design’s error-control specification may not require the trial to stop when the futility boundary is crossed. The simulation must represent the policy it is intended to evaluate: if crossing futility is specified to stop a path, record that stop; if continuation is permitted, encode that alternative explicitly. Do not label a boundary as nonbinding and then assume, without stating it, that every crossing ends the path.

The algorithm does not verify that the boundaries are statistically appropriate, that the simulated statistics were calculated correctly, or that the simulated path reflects the intended data-generating assumptions. It only implements the supplied rule. Those upstream choices must be checked separately. Clear decision records make such checks possible by preserving the look and reason rather than returning only a single success indicator.

  • Common mistake: “The path has a large statistic at the final look, so it is an efficacy success.” Correction: apply the stopping rule in order and retain the first decision. If an earlier futility stop occurred, a later value cannot convert that path to efficacy success.
  • Common mistake: “No boundary was crossed at an interim look, so I can fill in the reason later from the final statistic.” Correction: continue only while the path is active, and assign the maximum-look reason only after the final boundary check finds no crossing.
  • Common mistake: treating a missing statistic as if it fell between the boundaries. Correction: flag the path as invalid or handle it under an explicit missing-data policy; do not silently treat missingness as continuation.
Key takeaway: Evaluate each valid path in planned-look order, record its first stopping condition once, and keep stopping look, stopping reason, and final outcome as separate fields. At the final look, distinguish a boundary-triggered stop from completion without a crossing.

Check Your Understanding

Answer the questions using the definitions and hypothetical three-look boundaries in this tutorial. Suggested solutions follow each question.

  1. A path has \(Z_1=0.50\), \(Z_2=2.25\), and \(Z_3=0.10\). What are its stopping look, reason, and final outcome?
    Solution: At look 1, the value is between \(-0.50\) and \(2.80\), so the path continues. At look 2, \(2.25 \ge 2.20\), so it stops at look 2 for efficacy and is an efficacy success. The look-3 value is not used to revise the decision.
  2. A path has \(Z_1=0.30\), \(Z_2=0.10\), and \(Z_3=1.90\). What reason should be recorded at the end?
    Solution: No boundary is crossed: \(1.90 < 2.00\) and \(1.90 > -0.50\) at look 3, and the earlier values also lie between their boundaries. Record stopping look 3, reason “maximum look,” and outcome “no efficacy success.”
  3. Why is \(Z_k \ge u_k\), rather than \(Z_k > u_k\), used for efficacy in this specification?
    Solution: The stated rule includes equality as a crossing. A value exactly equal to the boundary must therefore stop for efficacy; using a strict inequality would implement a different rule.
  4. A path crosses the futility boundary at look 1 but has an efficacy-crossing value at look 3. Which decision is recorded, and why?
    Solution: Record futility at look 1 and no efficacy success. The rule is based on the first crossing, and the path is inactive after that decision, so look 3 cannot overwrite it.
  5. A statistic is missing at look 2, while the look-1 value did not cross a boundary. Should the path automatically continue to look 3?
    Solution: No. A missing value is not evidence that the statistic fell between the boundaries. Flag or handle the path under an explicitly specified missing-data policy instead of silently classifying it as continued.
Clinical Biostats