Files: use81.m
Back to main

QuickCheck Tutorial 8

Generators - Random Functions

Currently Quickcheck only has default generators for random functions that have 0 to 10 inputs, 1 output, and is in forward mode. This generated function can run on any type of inputs, but the output must be a type for which there is a custom/default generator.

The output may be indepedent of zero or more of the input arguments. By this we mean that the value of an input argument may have no bearing upon the calculation of the output. There is a 5% chance per argument of this occurring.

An example (use81.m)
:- module use81.

:- interface.

:- use_module io.

:- pred main(io__state, io__state).
:- mode main(di, uo) is det.

%---------------------------------------------------------------------------%

:- implementation.

:- import_module int, char, std_util, list.
:- import_module qcheck, rnd.

:- type strange(T1, T2)
        --->    wierd(T1, T2, T1).

main -->
        qcheck(qcheck__f(prop1), "prop1", 1000, [], []),
        qcheck(qcheck__f(prop2), "prop2", 1000, [], []),
        qcheck(qcheck__f(prop3), "prop3", 1000, [], []),
        qcheck(qcheck__f(prop4), "prop4", 1000, [], []).

:- func prop1( func(strange(int, char), int) = list(int) ) = property.
:- mode prop1( in( func(in,in)=out is det) ) = out is det.
prop1(FFF) = 
        FFF(wierd(1, '0', 2), 999) `===` FFF(wierd(1, '0', 2), 999).

:- func prop2(func(strange(int, char), int) = list(int)) = property.
prop2(FFF) = 
        (if     FFF(wierd(1, '0', 2), 999) = FFF(wierd(1, '0', 2), 888)
         then
                [ info(univ("equal")) | [yes] ] 
         else
                [ info(univ("not equal")) | [yes] ] 
        ).

:- func prop3(func(int) = int) = property.
prop3(FFF) = 
        (if     FFF(1) = FFF(0)
         then
                [ info(univ("equal")) | [yes] ]
         else
                [ info(univ("not equal")) | [yes] ]
        ).
        
:- func prop4(func(int, int) = int) = property.
prop4(FFF) = 
        (if     FFF(101, 10) = FFF(11, 15)
         then
                [ info(univ("equal")) | [yes] ]
         else
                [ info(univ("not equal")) | [yes] ]
        ).      

A sample output:

Test Description : prop1
Number of test cases that succeeded : 1000
Number of trivial tests : 0
Number of tests cases which failed the pre-condition : 0
Distributions of selected argument(s) : 

Test Description : prop2
Number of test cases that succeeded : 1000
Number of trivial tests : 0
Number of tests cases which failed the pre-condition : 0
Distributions of selected argument(s) : 
256     "equal"
744     "not equal"

Test Description : prop3
Number of test cases that succeeded : 1000
Number of trivial tests : 0
Number of tests cases which failed the pre-condition : 0
Distributions of selected argument(s) : 
60     "equal"
940     "not equal"

Test Description : prop4
Number of test cases that succeeded : 1000
Number of trivial tests : 0
Number of tests cases which failed the pre-condition : 0
Distributions of selected argument(s) : 
1     "equal"
999     "not equal"

prop1/1 just shows that given the same input, the output of the sample function is the same.

prop3/1 shows that given different input, the random function will usually give different output (940/1000 cases). For the rest 60/1000 cases, either the output is independent of input (most likely). Or it just so happens the output is the same for FFF(0) and FFF(1). (Note 60/1000 is roughly 5%)

prop2/1 shows 256/1000 cases shows that the random function returned the same output for different inputs. The real differenct between prop3/1 and prop2/1 is that the output of prop2/1 is list(int), which means the chance of generating [] is high (50% chance), and that's where 256/1000 cases come from.

prop4/1's random function takes two inputs, the chance of both inputs being independent of output is less compare to a random function which only takes 1 input. e.g.:
FFF(in)     = out, out independent of in is 5% chance
FFF(in, in) = out, out independent of in is 5% * 5% chance