Testcase generation for random inputs.
Overview
tgen is a C++ library to help you generate random stuff, useful for testcase generation (such as jngen or testlib). The code is in a single file tgen.h, that should be added to your directory.
The first thing is to register the generator. That defines the seed for random generation and parses the opts.
tgen uses a global RNG and generator registry; register_gen and subsequent generation are not thread-safe. Use one generator instance per process (or external synchronization) in multi-threaded programs.
There are:
and operations for specific data types:
Selected operations have benchmarks.
Type generators and values
List, string, permutation, pair, and graph generators describe a set of valid values under constraints. Calling gen() on such a generator samples uniformly at random among valid values (where the API documents uniformity). Static helpers such as gen_skewed, get_connected, geometry primitives, and gen_partition_fixed_size_fast are intentionally not uniformly random; see each function's documentation.
Let's see an example with tgen::list:
This will create a list generator representing the set of all lists with 10 values from 1 to 100.
Every generator of type Gen has a method gen(), that returns a Gen::value from the set of valid elements for the current restrictions. For constraint-based generators, gen() is uniformly random over that set. A Gen::value can be fed to std::cout to be printed.
In our example, we can call gen() to generate and print a random list of 10 elements from 1 to 100.
std::cout << t.
gen() << std::endl;
value gen() const
Generates a uniformly random value from the set of valid lists.
The nice thing is that we can add restrictions (specific to each type) to the generator, shrinking the set of valid lists. For example, we can add the restriction that the first and second elements of the list have to be the same.
list & equal(int idx_1, int idx_2)
Restricts generator s.t. values at two indices are equal.
The returned value can also be modified by some deterministic operations (specific to each type).
value & reverse()
Reverses the list.
Finally, there can also be random operations.
std::cout << inst.
pick() << std::endl;
T pick() const
Returns a uniformly random element.
Combining everything into one line:
std::cout << tgen::list<int>(10, 1, 100)
.equal(0, 1)
.gen()
.reverse()
.pick()
<< std::endl;
Complexity notation
Documented time complexities treat associative-container operations as O(log n), as with std::map and std::set. Some implementations use std::unordered_map or std::unordered_set for performance; the stated bounds are unchanged (we do not use O(1) average-case notation for those paths).
Union-find (detail::dsu) find and unite are documented as O(alpha(n)) amortized per operation (inverse Ackermann), not O(1).
Examples
Opts configuration
#include "tgen.h"
#include <iostream>
int main(int argc, char** argv) {
}
T next(T right)
Returns a random number smaller than value.
T opt(size_t index, std::optional< T > default_value=std::nullopt)
Gets opt by key.
void register_gen(int argc, char **argv)
Sets up the generator.
Calling this code with ./a.out -n 100 will generate a random number from 1 to 100.
Generation
Random 20 distinct values from 1 to 100.
std::cout <<
list & all_different()
Restricts generator s.t. all values are different.
67 96 80 11 46 52 42 2 93 1 28 3 48 82 90 99 53 98 94 88
Skewed connected graph on 10 vertices and 15 edges.
static value gen_skewed(int n, int m, int elongation, int spread, bool is_directed=false)
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
1 3
6 8
7 9
5 7
4 6
2 4
Random palindrome of length 7.
str & palindrome(int left, int right)
Restricts generator s.t. range is a palindrome.
value gen() const
Generates a uniformly random value from the set of valid strings.
Random 3 runs of 4 equal numbers. Values between runs are different.
std::cout <<
list & equal_range(int left, int right)
Restricts generator s.t. all values at index range are equal.
list & different(std::set< int > indices)
Restricts generator s.t. all values in index set are different.
Random DNA sequence of length 8 with no equal adjacent values.
for (
int i = 1; i < 8; i++) s2.
different(i - 1, i);
std::cout << s2.
gen() << std::endl;
Random binary sequence of length 10 with 5 1's that starts with 1.
std::cout <<
return std::accumulate(vec.begin(), vec.end(), 0) == 5;
}, 100) << std::endl;
auto gen_until(Pred predicate, int max_tries, Args &&...args) const
Generates a random value from the valid set until a condition is met.
auto to_std() const
Converts the list to a std::vector.
list & fix(int idx, T val)
Restricts generator s.t. value at index is fixed.
Generates a simple polygon given coordinate range.
std::vector< point< long long > > random_simple_polygon(int n, long long min_coord, long long max_coord)
Generates a random simple polygon given coordinate range.
Printer helper for standard types.
Example generated polygon
Random 1-based permutation of size 5 with only one cycle.
permutation & cycles(const std::vector< int > &cycle_sizes)
Restricts generator s.t. cycle sizes are fixed.
Inverse of a random odd permutation of size 5.
.
gen_until([](
const auto &perm) {
return perm.parity() == -1; }, 100)
.inverse() << std::endl;
Random prime in [1, 1e18].
uint64_t gen_prime(uint64_t left, uint64_t right)
Generates a random prime in given range.
Largest prime gap that fits in uint64_t.
std::cout << l << " " << r << " " << r - l << std::endl;
std::pair< uint64_t, uint64_t > prime_gap_upto(uint64_t right)
Largest prime gap up to given number.
6787988999657777798 6787988999657779306 1508
Random partition of 10 into 2 parts in [3, 7].
std::vector< int > gen_partition_fixed_size(int n, int k, int part_left=0, std::optional< int > part_right=std::nullopt)
Generates a random partition with fixed size of a number.
Random numbers in [0, 1e30].
std::cout <<
tgen::str(
"0 | [1-9][0-9]{0,%d} | 10{%d}", 30 - 1, 30).
gen_list(3) << std::endl;
auto gen_list(int size, Args &&...args) const
Generates a list of several generation calls.
395192209976851520716904879188 507650968099964477977292350849 549612473618635975427061717252
Random perfect matching of K_10.
for (int i = 0; i < 5; ++i)
std::cout << g.
gen() <<
"," << g.gen() <<
" ";
Distinct generator for discrete uniform functions.
auto gen()
Generates a distinct value.
All primes in [1, 10], in order.
auto gen_all()
Generates all distinct values left to generate.
5 random square numbers in [1, 1e4].
return x * x;
}).gen_list(5) << std::endl;
Some random parenthesis sequences.
std::string gen_parenthesis(int size)
Generates a random valid parenthesis sequence.
auto gen_list(int size)
Generates a list of several distinct values.
()(()) (())() (()()) ((())) ()()()
All pairs (a, b) in [1, 3] with a <= b.
std::cout << tgen::pair<int>(1, 3).leq().distinct().gen_all().separator('|') << std::endl;