Did you know ... Search Documentation:
random_terms.pl -- Random term generator
PublicShow source

This module generates random terms intented to test predicates that manage arbitrary terms. Think of variant detection (=@=/2), factorization, etc. The generated terms contain:

  • Actually shared subterms (same cell reachable via multiple paths).
  • Equivalent-but-not-shared subterms (fresh copies of earlier subterms).
  • Cyclic subterms (back-references to an ancestor under construction).
  • A sprinkling of fresh variables at the leaves.

Design

During generation we thread two lists:

  • Done — completed compound subterms. New subterms may either share these (unify with the same cell) or take a copy (duplicate_term/2, structurally equivalent but disjoint even for ground subterms — copy_term/2 would leak sharing here).
  • Anc — currently under-construction ancestors. A cycle back-reference simply unifies the new subterm with one of these, which produces a real cyclic term because the ancestor already contains the argument slot being filled.

At every non-leaf point a weighted choice is made among {leaf, share, copy, cycle, compound}. Options that are unavailable (empty pool / empty ancestor stack) are dropped from the choice rather than having their probability mass leak into the remaining options — otherwise early nodes, where the completed pool is still empty, would collapse into trivial self-cycles.

The compound weight is scaled by depth_decay^Level, where Level is the distance from the root. This keeps the root strongly biased towards compounds (avoiding trivial one-leaf terms) while making the probability of descending further vanish geometrically with depth.

Source random_term(-Term, +Options) is det
Generate a random term. Options override the defaults below and may be given either as an option list or as a dict. Weigths (w_*) are handled as relative weights in two groups:
  • w_leaf, w_share, w_copy, w_cycle and w_compound control the (compound) shape of the resulting term.
  • w_atom, w_int, w_float, w_rational and w_string control what leaf node is generated after the group above decided to create a leaf.

Defaults:

#{
  depth:        5,          % maximum recursion depth
  depth_decay:  0.5,        % w_compound is scaled by this per level
  max_arity:    3,          % maximum compound arity
  functors:     [f,g,h,p,q],
  atoms:        [a,b,c],
  max_int:      100,        % random integer leaves in 0..max_int
  p_zero_arity: 0.1,	  % fraction on zero-arity compounds.
  w_leaf:       10,         % choice weights
  w_share:      30,
  w_copy:       15,
  w_cycle:      15,
  w_compound:   50,
  w_var:        10,         % leaf-type weights
  w_atom:       10,
  w_int:        10,
  w_float:      10,
  w_rational:   10,
  w_string:     10
}
Source choices(+Level, +Params, +Done, +Anc, -Cs) is det[private]
Construct a list of choices Cs as Weight-Action, where Action is one of leaf, compound, share, copy, cycle.