tests/testthat/test-dual.R

# ==========================================================================
# Dual system tests
# ==========================================================================


test_that("dual of series is parallel-like via phi", {
  sys <- series_dist(iid_exp_components(3))
  dsys <- dual(sys)
  # dual phi(state) = 1 - phi(1 - state); series.phi(1-state) = 1 iff all 1 flipped, i.e., state = 0
  expect_equal(phi(dsys, c(0, 0, 0)), 0L)
  expect_equal(phi(dsys, c(1, 0, 0)), 1L)
  expect_equal(phi(dsys, c(1, 1, 1)), 1L)
})


test_that("dual of k-of-m satisfies phi identity", {
  sys <- kofn_dist(k = 2L, iid_exp_components(4))
  dsys <- dual(sys)
  for (a in 0:1) for (b in 0:1) for (c in 0:1) for (d in 0:1) {
    state <- c(a, b, c, d)
    expect_equal(phi(dsys, state), 1L - phi(sys, 1L - state))
  }
})


test_that("dual of dual equals original (involution)", {
  sys <- kofn_dist(k = 2L, iid_exp_components(3))
  dd <- dual(dual(sys))
  # Either returns the same object (coherent_dist path via min_cuts) or a
  # double-wrapped equivalent. Check phi-equivalence.
  for (a in 0:1) for (b in 0:1) for (c in 0:1) {
    state <- c(a, b, c)
    expect_equal(phi(dd, state), phi(sys, state))
  }
})


test_that("dual_of_system inherits dist_structure defaults", {
  sys <- series_dist(iid_exp_components(3))
  dsys <- dual(sys)  # falls through to coherent_dist method producing a new coherent_dist
  expect_true(is_dist_structure(dsys))
  expect_equal(ncomponents(dsys), 3L)
})


test_that("coherent_dist dual swaps paths and cuts", {
  sys <- coherent_dist(
    min_paths = list(c(1L, 2L), c(3L)),
    components = iid_exp_components(3)
  )
  dsys <- dual(sys)
  # dual min_paths should equal original min_cuts
  expect_setequal(
    lapply(min_paths(dsys), sort),
    lapply(min_cuts(sys), sort)
  )
})


test_that("dual_of_system has component() (regression: lazy-wrapper dispatch)", {
  # The package-level closed-form classes route through dual.coherent_dist
  # and produce a fresh coherent_dist (not a dual_of_system), so they do
  # not exercise the lazy-wrapper path. This test directly constructs a
  # dual_of_system to verify that component() dispatches correctly --
  # before the C1 fix in v0.5.x, component(dual_of_system_obj, j) errored
  # with "no applicable method", breaking surv() / sampler() defaults
  # for any user-defined dist_structure subclass that did not also
  # inherit coherent_dist.
  sys <- series_dist(iid_exp_components(3))
  dsys <- structure(
    list(original = sys, m = ncomponents(sys)),
    class = c("dual_of_system", "dist_structure",
              "univariate_dist", "continuous_dist", "dist")
  )

  expect_no_error(component(dsys, 1L))
  expect_identical(component(dsys, 1L), component(sys, 1L))
  expect_identical(component(dsys, 2L), component(sys, 2L))
  expect_identical(component(dsys, 3L), component(sys, 3L))
})

Try the dist.structure package in your browser

Any scripts or data that you put into this service are public.

dist.structure documentation built on May 13, 2026, 1:07 a.m.