chickadee » data-generators

data-generators

Requirements

random-bsd, numbers

Repository

https://bitbucket.org/certainty/data-generators/overview

Authors

David Krentzlin

Introduction

This egg provides primitives and combinators to generate random data. That may be useful for testing or other occasions where you just need a way to quickly generate data.

Examples

data-generators

(use json data-generators)

;; generate a json document
(define (gen-json-doc #!optional (nesting 5))
  (generator
   (with-output-to-string
     (lambda ()  (json-write (<- (gen-json-value nesting)))))))

;; this is the only tricky part
;; we need to stop the recursion at a certain level of nesting and yet
;; we want to reduce the construction of generators to a minimum
(define (gen-json-value nesting)
  (let ((scalar (gen-json-scalar)))
    (if (positive? nesting)
        (gen-sample-of (gen-json-complex (sub1 nesting)) scalar)
        scalar)))

(define (gen-json-scalar)
  (gen-sample-of (gen-json-null) (gen-json-string) (gen-json-number)))

(define (gen-json-string)
  (with-size (range 0 20)
    (gen-string-of (gen-char #\A #\z))))

(define (gen-json-null)
  (gen-constant (void)))

(define (gen-json-number)
  (gen-sample-of (gen-fixnum) (gen-real)))

(define (gen-json-complex nesting)
  (gen-sample-of (gen-json-object (sub1 nesting)) (gen-json-array (sub1 nesting))))

(define (gen-json-object nesting)
  (gen-vector-of (gen-pair-of (gen-json-string) (gen-json-value (sub1 nesting)))))

(define (gen-json-array nesting)
  (gen-list-of (gen-json-value (sub1 nesting))))

;; now let's print our documents
(with-size (range 0 20)
  (gen-for-each 10 print (gen-json-doc 10)))

data-generators-literals

(use data-generators data-generators-literals)

;; create a generator using the generator literal 
(print (<- #g[0 .. 100]))

;; create a generator using the range literal
(print (<- (gen-list-of (gen-fixnum #i[0 ... 100])))

API

Generators

A generator is a means to create random values that possibly adhere to some constraints. By nature a generator represents an infinite stream of random values.

(generator ?body ...)syntax

Creates a new generator. You can use this to define your own generators.

Example:

(define (my-gen start)
 (generator (+ start 42))

(<- (my-gen 10)) ;=> 52

Extracting data from generators

<- genprocedure

Invokes the generator gen once and returns that value.

<- amount genprocedure

Invokes the generator gen amount times and returns a list of values

gen-for-each n proc genprocedure

Invokes the generator gen n times and applies proc to each value in turn. proc must be a procedure that takes two arguments. The first argument will be the value and the second argument will be the round in which the value was generated.

Ranges

Many generators accept a range argument that specifies the upper and lower bounds. You can use the following procedures to work with ranges.

range lower upperprocedure

Creates a range that covers values from lower to upper. There are three variations of this:

  • lower is #f and upper is not #f -> creates a range from (gen-current-fixnum-min) till upper
  • lower is not #f and upper is #f -> creates a range from lower till (gen-current-fixnum-max)
  • lower is not #f and upper is not #f -> creates a range from lower till upper

Generic generator

The library provides a generic generator procedure that is able to build the correct generator based on the type of the supplied arguments.

gen lower upperprocedure

Creates a generator that can be created for the given argument types. Currently supported types are:

  • fixnum
  • flonum
  • char
gen rangeprocedure

Creates a generator that can be created for the given range. It dispatches on the type of the lower bound. Currently supported types are:

  • fixnum
  • flonum
  • char
register-generator-for-type! type? genprocedure

Registers a type-predicate with a generator. When the generic generator procedure gen is invoked, it will dispatch on the first argument using the registered type-predicates.

Parameters

gen-current-fixnum-minparameter

The smallest fixnum that should be generated.

gen-current-fixnum-maxparameter

The biggest fixnum that should be generated

Primitives

gen-constant valueprocedure

Generator that always returns value.

fixnums ...procedure

Alias for gen-fixnum.

gen-fixnumprocedure

Generator for a fixnum between gen-current-fixnum-min and gen-current-fixnum-max.

gen-fixnum rangeprocedure

Generator for a fixnum within the given range

gen-fixnum lower-bound upper-boundprocedure

Generator for a fixnum between lower-bound and upper-bound

odd-fixnums ...procedure

Alias for gen-odd-fixnum.

gen-odd-fixnum ...procedure

This generator supports all the variations for gen-fixnum but it will only yield odd numbers

even-fixnums ...procedure

Alias for gen-even-fixnum.

gen-even-fixnum ...procedure

This generator supports all the variations for gen-fixnum but it will only yield even numbers

gen-int8procedure

Generator for a fixnum between -127 and 127.

gen-uint8procedure

Generator for a fixnum between 0 and 255.

gen-int16procedure

Generator for a fixnum between -32767 and 3276.

gen-uint16procedure

Generator for a fixnum between 0 and 65535.

gen-int32procedure

Generator for a fixnum between -2147483647 and 2147483647.

gen-uint32procedure

Generator for a fixnum between 0 and 4294967295.

gen-int64procedure

Generator for a fixnum between -9223372036854775807 and 9223372036854775807.

gen-uint64procedure

Generator for a fixnum between 0 and 18446744073709551615.

gen-realprocedure

Generator for a real number between 0.0 and 1.0.

gen-real rangeprocedure

Generator for a real number in the given range.

gen-real lower-bound upper-boundprocedure

Generator for a real number between lower-bound and upper-bound.

gen-flonumprocedure

Generator for a flonum between 0.0 and 1.0 or one of the special flonums +nan.0 +inf.0 and -inf.0.

gen-flonum rangeprocedure

Generator for a flonum in the given range.

gen-flonum lower-bound upper-boundprocedure

Generator for a flonum between lower-bound and upper-bound.

gen-rationalprocedure

Generator for a rational number

gen-rational nom-gen denom-genprocedure

Generator for a rational number where the nominator is generated with nom-gen and the denominator is generated with denom-gen.

chars ...procedure

Alias for gen-char.

gen-charprocedure

Generator for a character from char-set:graphic.

gen-char charsetprocedure

Generator for a character from the char-set charset.

gen-char rangeprocedure

Generator for a character in the given range.

gen-char lower-bound upper-boundprocedure

Generator for a character from the char-set build from lower-bound to upper-bound. lower-bound must be <= upper-bound as compared with char<=?.

Example:

(gen-char #\a #\z)
booleansprocedure

Alias for gen-bool.

gen-boolprocedure

Generator for a random boolean value

gen-procedureprocedure

Generator for a procedure. This is equivalent to (gen-procedure (<- (gen-fixnum 0 max-arity)) (gen-bool)).

gen-procedure arity return-genprocedure

Generator that generates procedures with the given arity with 0 <= arity <= max-arity. max-arity is currently 20. The procedures that are generated return a value that is created by invoking return-gen.

gen-sample candidatesprocedure

Generator that draws a random sample from the list of candidates.

gen-seriesprocedure

Generator that returns values from the series starting at gen-current-fixnum-min till gen-current-fixnum-max by applying add1 in each step.

Example:

;; create lists with increasing size from 1 to 10
(<- 10 (gen-list-of (fixnums) (gen-series 1 10 add1)))
gen-series start end stepprocedure

Generator that generates values from start to end with steps as specified by the one-argument-procedure step. The step procedure gets the current value during each application of the generator and must return the next possible value. The generator automatically wraps around and starts over if the end of the series has been reached.

Combinators

gen-current-default-sizeparameter

A generator that must return a fixnum. It's used to determine the size for generators that can have a length. This defaults to (gen-uint8).

gen-values-of #!rest gensprocedure

Generator that returns multiple values. Each value is generated with the given generators

gen-pair-of car-gen cdr-genprocedure

Generator for a pair where the car is generated with car-gen and the cdr is generated with with cdr-gen.

gen-sample-of #!rest gensprocedure

Generator that draws a random generator from the list of possible generators and invokes it once.

gen-tuple-of #!rest gensprocedure

Generator for a tuple where each element is generated by the given generators.

gen-string ...procedure

Alias for gen-string-of.

(gen-string-of char-gen #!optional (size (gen-current-default-size)))procedure

Generator for a string where each character is generated from char-gen. The size parameter specifies the size of the strings that are generated. It is expected to be a thunk that returns the size as a fixnum. See with-size for a more convenient way to adjust this.

gen-symbol ...procedure

Alias for gen-symbol-of

(gen-symbol-of #!optional (char-gen (gen-char char-set:letter+digit)) (size (gen-current-default-size)))procedure

Generator for a symbol where each character is generated from char-gen. The size parameter specifies the size of the strings that are generated. It is expected to be a thunk that returns the size as a fixnum. See with-size for a more convenient way to adjust this.

gen-keyword ...procedure

Alias for gen-keyword-of

(gen-keyword-of #!optional (char-gen (gen-char char-set:letter+digit)) (size (gen-current-default-size)))procedure

Generator for a keyword where each character is generated from char-gen. The size parameter specifies the size of the strings that are generated. It is expected to be a thunk that returns the size as a fixnum. See with-size for a more convenient way to adjust this.

(gen-list-of gen #!optional (size (gen-current-default-size)))procedure

Generator for a list where each element is generated with the given generator gen. The size parameter specifies the size of the list that is generated. It is expected to be a thunk that returns the size as a fixnum. See with-size for a more convenient way to adjust this.

(gen-alist-of car-gen cdr-gen #!optional (size (gen-current-default-size)))procedure

Generator for an alist where each car is generated with car-gen and each cdr is generated with with cdr-gen. The size parameter specifies the size of the list that is generated. It is expected to be a thunk that returns the size as a fixnum. See with-size for a more convenient way to adjust this.

(gen-vector-of gen #!optional (size (gen-current-default-size)))procedure

Generator for a vector where each element is generated with the given generator gen. The size parameter specifies the size of the vector that is generated. It is expected to be a thunk that returns the size as a fixnum. See with-size for a more convenient way to adjust this.

(gen-hash-table-of key-gen value-gen #!optional (size (gen-current-default-size)) (equal? eq?))procedure

Generator for a hash-table where each key is generated by key-gen and each value is generated by value-gen. The size parameter specifies the size of the hash-table that is generated. The equal? parameter is passed directly to make-hash-table. It is expected to be a thunk that returns the size as a fixnum. See with-size for a more convenient way to adjust this.

gen-record ctor #!rest slot-gensprocedure

Generator for a record that is created with the given ctor where each slot is generated with the given slot-gens.

gen-transform transformer genprocedure

Generator that retrieves values from gen and applies transformer to this value.

;; gen positive fixnums

(gen-transform abs (fixnums))
(with-size size-spec ...)syntax

Use this to constrain the size of the data generated by the combinators. size-spec is either a fixnum a range or a generator. If it is a fixnum all data will be generated with the size equal to that fixnum. If it is a range, all data will be generated with a size that lies within that range. If it's a generator, this generator is expected to return the size.

Networking generators

In order to use these you need to (use data-generators-net).

gen-ipv4-addressprocedure

Creates a generator that returns a string representing a dotted quad ipv4 address.

Defining your own generators

To define your own generators you can use the generator-syntax.

(define (gen-foo) (generator "foo"))

(with-size 3 (gen-list-of (gen-foo))) ;=> ("foo" "foo" "foo")

Reader extensions

Optionally you can use data-generators-literals to use reader-extensions that allow you to create ranges and generators.

#i[x .. y]syntax

Creates a range from x to y inclusive.

#i[ .. y]syntax

Creates a range from (gen-current-fixnum-min) to y inclusive.

#i[x .. ]syntax

Creates a range from x to (gen-current-fixnum-max) inclusive.

#i[x ... y]syntax

Creates a range from x to y exclusive.

#i[ ... y]syntax

Creates a range from (gen-current-fixnum-min) to y exclusive.

#i[x ... ]syntax

Creates a range from x to (gen-current-fixnum-max) exclusive.

#g[range-exp]syntax

Creates a generator by applying gen to the given range-expression. The range-expression is the same that the #i[]-reader-macro supports. It expands to (gen range-expression).

Example:

(use data-generators data-generators-literals)

(<- #g[1 .. 10])
(<- #g[#\a ... #\z])
(<- #g[1.0 .. 10.3])

See also

For a very exhaustive and systematic approach to all kinds of random sources see: srfi-27

License

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.
A full copy of the GPL license can be found at
<http://www.gnu.org/licenses/>.

Contents »