Sign inSign up

eagleoutice/constrainr

By eagleoutice

•Updated 12 days ago

Image
0

57

eagleoutice/constrainr repository overview

docker run --rm -v "$PWD:/work" constrainr -- analysis.R       # infer, next to the script
docker run --rm -v "$PWD:/work" constrainr -- check analysis.constrained.R

This is WIP.

The image has R 4.5.1 and ~50 common CRAN packages (docker/packages.txt) from the pinned P3M snapshot CRAN_SNAPSHOT, in a layer cached independently of the code. Other packages are installed from the same snapshot.

Options: --out dir, --runs n (2), --checks n (2), --timeout seconds (300), --margin x (0.1), --no-demand, --no-generalize, --no-hoist, --strict (all three), --environment, --install-packages (default in Docker), --quiet.

Output: <script>.constrained.R (plain R, runs without constrainR) and <script>.constraints.json.

⁠How it works

  1. Select: assignments, arguments of output and plot calls, top-level echoes (flowR dependencies query).
  2. Classify: skip flowR constants; mark random/system/network/option inputs volatile, values depending on read data external (input-sources query); pure expressions (flowR call properties) may be re-evaluated in a check.
  3. Demand (src/demand.ts): what the rest of the script needs of each value, propagated backwards over the dataflow graph from outputs. d$a, d[["a"]] and the columns dplyr verbs read (linked by flowR) need part a; nrow/length the size; names the names; row subsets and column-preserving verbs pass needs through; unused values need nothing. Anything not understood (unknown calls, tidyselect helpers, get, ...) needs everything. --environment counts the variables left at the end as results (for sourced scripts).
  4. Trace: run the instrumented script --runs times, aggregate values per flowR node id; lists and data frames also per named part.
  5. Infer one ladder of constraints per needed facet, strongest first: the container (type, the needed parts, size) and each needed part. Values computed from the code alone: exact, one-of, tolerance, range. External values are generalized: short categorical values stay exact, others keep their domain (categories seen), numbers a range widened by --margin of their spread, then their sign and integrality, vectors any non-zero length. Statistical tests: significance (< 0.001, then 0.01, 0.05, 0.1). Then structure, shape.
  6. Rewrite (src/rewrite.ts): constraints are conjunctions of atoms, simplified before rendering (identities absorb other facts, exact names imply needed ones, ranges imply bounds). Aliases, parts (effect$p.value) and pure values of exactly checked definitions are implied.
  7. Move up (src/hoist.ts): a pure value is checked right after the last of its inputs is defined when effects (output, files, plots) lie in between, so a violation stops the script before them; a pure value in a for loop over a:b/seq_* is checked for all iterations before the loop. Checks never move above code loading packages or redefining a function the value calls.
  8. Validate: run the constrained script --checks times, weaken each violated facet one level, repeat.

--strict turns off 3, the generalization in 5 and 7: every observed property, exact first, checked in place. Rerunning on a constrained script strips the old checks first.

src/flowr.ts is the only module that talks to flowR's analyzer, graph and queries.

Tag summary

Content type

Image

Digest

sha256:006e1c879…

Size

539.3 MB

Last updated

12 days ago

docker pull eagleoutice/constrainr