Skip to contents

Construct the initial Gabriel graph, adapt local scales and prune edges, returning graphs, affinities and diagnostics. By default, proposed bridge edges are protected so that pruning retains connectivity, and the audited retry-power numerical policy permits one checked retry after an eligible solver rejection. These are explicit variants of reference IAN.

Usage

create.ian.graph(
  X,
  distances = NULL,
  specimen.ids = NULL,
  participant.ids = NULL,
  graph = NULL,
  diagnostics = c("summary", "full"),
  backend = NULL,
  max.solves = 10000L,
  numerical.policy = "IAN evaluated-LP retry-power 0.1",
  preserve.connectivity = TRUE
)

Arguments

X

Finite numeric specimen-by-feature matrix, at least two rows and one column. There is no fixed experimental row cap. Input size must fit R/native index representations and available memory. Dense distances and affinities require quadratic storage: each n-by-n double matrix uses 8*n*n bytes before overhead. Several matrices/copies coexist; this is not a peak-memory estimate. Initial Gabriel construction has cubic worst-case cost. Full diagnostics retain additional dense data. See the backend guide for tested sizes.

distances

Optional unsquared distance matrix or dist. When absent, Euclidean distances are computed with stats::dist(X). Supplied distances are used exactly; duplicate feature rows must have identical distance rows. Coordinates are always required to define duplicate profiles. Row/column order must match X; named distances must match specimen IDs.

specimen.ids

Unique nonempty IDs; defaults to row names or row numbers.

participant.ids

Optional specimen-level nonempty IDs, possibly repeated.

graph

Reserved supplied-graph argument; currently must be NULL. The actual initial Gabriel graph is always constructed by IAN.

diagnostics

"summary" or "full"; full includes dense LP payloads.

backend

Optional path to the separately built dgraphs_ian.so module.

max.solves

Positive integer safety limit; reaching it returns refusal.

numerical.policy

Exactly "IAN evaluated-LP 1.0" (strict, without retries) or "IAN evaluated-LP retry-power 0.1" (default: one eligible checked retry).

preserve.connectivity

Logical scalar, default TRUE. Use FALSE for reference pruning, which may disconnect the graph. With TRUE, cache encountered bridges and skip them before testing each proposed edge's pruning eligibility. Check noncached edges in the current graph after preceding deletions. Skips do not consume the deletion allowance. All vertices are retained. An initially disconnected graph returns refusal. This explicit variant does not change the numerical solver policy.

Value

A list with complete, structured error, initial Gabriel graph, final_graph only on full completion, last_valid_graph (possibly partial), profile mapping, local scales and an affinity matrix distinct from metric edge lengths. Graph indices and mappings are one-based. Full traces retain original zero-based core indices and declare this in diagnostics. Summary diagnostics include per-solve status, acceptance, settings, residuals and iteration counts. Refusal and interruption return incomplete structured results; invalid R arguments error before native execution. Interrupts are checked at engine events; they do not interrupt an active solver call. In connectivity mode, diagnostics$connectivity contains protected.edges (one-based profile rows and IDs, first/last encounter iteration, count and first statistic), per-iteration history, and stop.reason. Iterations in this summary are one-based. Protected edges are encountered proposals, not necessarily edges that would pass the pruning criteria. Full traces also include every edge proposal and whether eligibility was tested. A complete pass with no deletion stops, including when statistical candidates remain protected. Partial results retain available protection diagnostics; final_graph remains NULL if later optimization or affinity construction fails.

Details

Build the optional module once with build.ian.backend() and pass its returned path as backend. The supported build target is macOS arm64. The function itself does not compile code, download dependencies or launch an external solver. See system.file("ian", "README.md", package = "dgraphs") for the numerical contract, setup requirements and bounded qualification.

Input rows are specimens; graph vertices are unique feature profiles in first-occurrence order. Always check complete before using final_graph. Invalid R arguments or an unavailable backend raise an R error. Numerical refusal and interruption during engine execution return an incomplete result with the available diagnostics. Memory exhaustion or process termination is not a recoverable-result guarantee.

The default numerical policy is IAN evaluated-LP retry-power 0.1. A rejected original return remains rejected. Its single eligible retry must itself pass strict solver success and the unchanged original-unit checks. numerical.policy="IAN evaluated-LP 1.0" together with preserve.connectivity=FALSE selects the previous strict/reference behavior. This public default adoption changes neither policy's implementation.

The returned top-level fields are complete, error, initial_graph, final_graph, last_valid_graph, mapping, scales, affinity, diagnostics and backend. Graphs are dgraph() objects with metric edge lengths in input distance units; affinity values are separate similarities. Mapping contains one-based representatives and member_to_profile, plus specimen, profile and participant IDs. Repeated participant IDs do not merge specimens. Error information contains kind, code and message. diagnostics$solver_history retains both accepted and rejected attempts. Backend information identifies the selected policies, source and settings. Checkpoint/resume is not exposed through this R interface.

Examples

# Set this variable to the path returned by build.ian.backend().
backend <- Sys.getenv("DGRAPHS_IAN_BACKEND")
if (nzchar(backend) && file.exists(backend)) {
  X <- rbind(c(0, 0), c(1, 0), c(2, 0), c(0, 0))
  fit <- create.ian.graph(X, backend = backend,
      specimen.ids = c("alpha", "beta", "gamma", "delta"))
  stopifnot(fit$complete)
  graph.edges(fit$initial_graph)
  graph.edges(fit$final_graph)
  fit$mapping$member_to_profile # Four specimens, three unique profiles.
  fit$diagnostics$connectivity$protected.edges
}