Skip to contents

Re-executes a design exactly as recorded in its execution receipt, passing the stored seed, stages, panels, and reps back to execute().

Usage

replay_design(
  x,
  frame,
  ...,
  fingerprint = c("error", "warn", "inform", "ignore"),
  links = NULL,
  targets = NULL
)

Arguments

x

A sampling_design carrying an execution receipt, as returned by read_design() for a file written from a tbl_sample. A tbl_sample is also accepted and is replayed from its own metadata, which is useful for verifying reproducibility without a file round trip.

frame

The sampling frame the receipt refers to: a data frame for a one-frame call, or the ordered list of stage frames for a call that supplied one register per stage. For a sample built by several calls, one element per call that read frames, in the form frame takes in write_design().

...

Must be empty. Arguments after it are matched by exact name.

fingerprint

How to respond when frame differs from the fingerprint stored in the design file: "error" (default), "warn", "inform", or "ignore".

The link table and the target register, for a shared-weight sample only. Both are required there and refused elsewhere, so a sample is never returned untransformed to a caller expecting a transformation. The result is checked against the integrity the file records.

Value

The replayed tbl_sample, or the rebuilt frame_stack for a frame collection. When the receipt carries a frame digest, the replay captures its own digest in the same mode ("summary" or "full") and compares pool sizes, targets, expected sizes and chances, plus chance quantiles or every unit's chance. A difference warns with samplyr_warning_replay_digest. That catches a frame saved without its fingerprint, and a version of samplyr or its dependencies that resolves the design differently. The comparison is skipped under fingerprint = "ignore" and once a frame difference has been reported.

Details

Given the same frame and compatible recorded implementations, the replayed sample is identical to the original: the same rows in the same order, the same weights and design columns, and the same .panel and .replicate assignments. Only the execution timestamp differs. Replay restores the execution-time RNG configuration and then the caller's RNG state. It warns when recorded R or package versions differ.

When the design was saved with a frame fingerprint, frame is compared against it before replaying. A differing frame still yields a valid sample, but not the recorded one, so the default is to error. Several frames are compared one by one, and a mismatch names the register by position and recorded label. A wrong number of frames is samplyr_error_replay_frame_count. After replaying, the row count is checked against the receipt's n_selected.

A chained sample, produced by several execute() calls, is replayed call by call, each under its own seed, stages and RNG kind. The first call and each continuation read the frames given here, a new phase reads the phase replayed before it, and a wave reads its replayed master. Inherited panels and replicates are carried rather than declared again. The fingerprints cover every call's frames, and the row count is checked after each call. An earlier call run without a seed is samplyr_error_receipt_no_seed. When a new phase was drawn from a sample modified after its execution, the record starts at that phase, and its frame must be the modified sample as the tbl_sample it was (samplyr_error_replay_phase_frame otherwise).

A chained receipt that does not record its earlier calls (a continuation of a modified sample, or a file written before receipts recorded earlier calls) is refused with class samplyr_error_receipt_chained. The refusal carries the final call's seed and stages as fields and gives the recipe. Rebuild the sample that call ran on by replaying its own receipt, or keep it when it was modified, since no receipt rebuilds a modified sample. Then run execute(earlier, frame, seed = seed, stages = stages) for a continuation, or execute(design, earlier, seed = seed) for a new phase. That reproduces the sample exactly under the same RNG kind, which the refusal names since a direct execute() does not set it.

A shared-weight sample re-executes the source selection against frame, then re-applies the recorded transformation to links and targets. Those are not in the file, so replay checks the source and the result against the hashes the file records. A source that does not reproduce means frame is wrong, and a result that does not means links or targets is.

A frame collection replays each component against its register, with frame a list named by component. Every component is checked before any runs. The results are stacked through stack_frames() rather than by restoring attributes, so a register that has lost the membership column, or whose key is no longer unique, is reported as that. Shared-weight samples and collections are accepted both from a file and live.

For a registered custom method, the receipt records a fingerprint of the implementation (the formals and body of the registered sample_fn and joint_fn). Replay refuses when the currently registered function differs, since identical registry metadata does not imply the same selections. The fingerprint normalizes formatting and comments and does not cover the enclosing environment, so a registered function that reads from its environment can change behavior without changing its fingerprint.

A panel assignment record naming an algorithm or schema version this samplyr does not know is samplyr_error_panel_record_unsupported. One that lacks what its stated version requires, or is not a set of named fields, is samplyr_error_panel_record_malformed. Neither is replayed under the current law or repaired, since the assignment stage decides the assignment units and filling in a missing one would replay a different assignment.

vignette("serialization") works through these cases with examples.

See also

write_design() and read_design() for the receipt round trip, validate_frame() for checking a frame against a design before executing.

Other serialization: as.list.sampling_design(), design_json(), write_design()

Examples

sample <- sampling_design() |>
  stratify_by(region) |>
  draw(n = 100) |>
  execute(bfa_eas, seed = 11, panels = 4)

path <- tempfile(fileext = ".json")
write_design(sample, path, frame = bfa_eas)

replayed <- replay_design(read_design(path), bfa_eas)
identical(replayed$ea_id, sample$ea_id)
#> [1] TRUE
identical(replayed$.panel, sample$.panel)
#> [1] TRUE

# One register per stage replays from the same ordered list
regions <- dplyr::distinct(bfa_eas, region)
two_stage <- sampling_design() |>
  add_stage(label = "Regions") |>
    cluster_by(region) |>
    draw(n = 3) |>
  add_stage(label = "EAs") |>
    draw(n = 5)

registers <- execute(two_stage, regions, bfa_eas, seed = 4)
write_design(registers, path, frame = list(regions, bfa_eas))
identical(
  replay_design(read_design(path), list(regions, bfa_eas))$ea_id,
  registers$ea_id
)
#> [1] TRUE

# A second phase replays both calls from the first phase's frame
phase1 <- sampling_design() |>
  stratify_by(region) |>
  draw(n = 300) |>
  execute(bfa_eas, seed = 7)
phase2 <- sampling_design() |>
  stratify_by(urban_rural) |>
  draw(n = 60) |>
  execute(phase1, seed = 8)
write_design(phase2, path, frame = bfa_eas)
identical(replay_design(read_design(path), bfa_eas)$ea_id, phase2$ea_id)
#> [1] TRUE

unlink(path)