switch to exact version of cython
[ieee754fpu.git] / src / ieee754 / fpcommon / test / case_gen.py
1 """FP Unit Test Infrastructure
2
3 allows testing of:
4
5 * random range against random range
6 * +/- 0, +/- inf, +/- NaN permutations, all tested against all permutations
7 * all of those permutations (+/- 0/inf/NaN) against the following:
8 - nearly zero (random variations)
9 - minimum non-zero exponent (random variations)
10 - nearly infinite (random variations)
11 - random versions of NaN (noncanonical NaN)
12 - random numbers (at the full range)
13
14 inversion of permutations also done, where appropriate (A,B and B,A)
15
16 single-operand version also supported
17
18 """
19
20 from ieee754.fpcommon.test.fpmux import runfp, repeat, pipe_cornercases_repeat
21
22 from random import randint
23 from random import seed
24
25 import sys
26
27 def corner_cases(mod):
28 return [mod.zero(1), mod.zero(0),
29 mod.inf(1), mod.inf(0),
30 mod.nan(1), mod.nan(0)]
31
32 def get_corner_cases(mod, single_op=False):
33 #corner cases
34 from itertools import permutations
35 cc = corner_cases(mod)
36 stimulus_a = [i[0] for i in permutations(cc, 2)]
37 if single_op:
38 return stimulus_a
39 stimulus_b = [i[1] for i in permutations(cc, 2)]
40 return zip(stimulus_a, stimulus_b)
41
42
43 def replicate(fixed_num, maxcount):
44 if isinstance(fixed_num, int):
45 return [fixed_num for i in range(maxcount)]
46 else:
47 return fixed_num
48
49 def get_rval(width):
50 mval = (1<<width)-1
51 return randint(0, mval)
52
53 def get_rand1(mod, fixed_num, maxcount, width, single_op=False):
54 stimulus_b = [get_rval(width) for i in range(maxcount)]
55 if single_op:
56 yield from stimulus_b
57 return
58 stimulus_a = replicate(fixed_num, maxcount)
59 yield from zip(stimulus_a, stimulus_b)
60 yield from zip(stimulus_b, stimulus_a)
61
62
63 def get_nan_noncan(mod, fixed_num, maxcount, width, single_op=False):
64 # non-canonical NaNs.
65 stimulus_b = [mod.set_exponent(get_rval(width), mod.max_e) \
66 for i in range(maxcount)]
67 if single_op:
68 yield from stimulus_b
69 return
70 stimulus_a = replicate(fixed_num, maxcount)
71 yield from zip(stimulus_a, stimulus_b)
72 yield from zip(stimulus_b, stimulus_a)
73
74
75 def get_n127(mod, fixed_num, maxcount, width, single_op=False):
76 # -127
77 stimulus_b = [mod.set_exponent(get_rval(width), -mod.max_e+1) \
78 for i in range(maxcount)]
79 if single_op:
80 yield from stimulus_b
81 return
82 stimulus_a = replicate(fixed_num, maxcount)
83 yield from zip(stimulus_a, stimulus_b)
84 yield from zip(stimulus_b, stimulus_a)
85
86
87 def get_nearly_zero(mod, fixed_num, maxcount, width, single_op=False):
88 # nearly zero
89 stimulus_b = [mod.set_exponent(get_rval(width), -mod.max_e+2) \
90 for i in range(maxcount)]
91 if single_op:
92 yield from stimulus_b
93 return
94 stimulus_a = replicate(fixed_num, maxcount)
95 yield from zip(stimulus_a, stimulus_b)
96 yield from zip(stimulus_b, stimulus_a)
97
98
99 def get_nearly_inf(mod, fixed_num, maxcount, width, single_op=False):
100 # nearly inf
101 stimulus_b = [mod.set_exponent(get_rval(width), mod.max_e-1) \
102 for i in range(maxcount)]
103 if single_op:
104 yield from stimulus_b
105 return
106 stimulus_a = replicate(fixed_num, maxcount)
107 yield from zip(stimulus_a, stimulus_b)
108 yield from zip(stimulus_b, stimulus_a)
109
110
111 def get_corner_rand(mod, fixed_num, maxcount, width, single_op=False):
112 # random
113 stimulus_b = [get_rval(width) for i in range(maxcount)]
114 if single_op:
115 yield from stimulus_b
116 return
117 stimulus_a = replicate(fixed_num, maxcount)
118 yield from zip(stimulus_a, stimulus_b)
119 yield from zip(stimulus_b, stimulus_a)
120
121
122 class PipeFPCase:
123 def __init__(self, dut, name, mod, fmod, width, fpfn, count,
124 single_op, opcode):
125 self.dut = dut
126 self.name = name
127 self.mod = mod
128 self.fmod = fmod
129 self.width = width
130 self.fpfn = fpfn
131 self.count = count
132 self.single_op = single_op
133 self.opcode = opcode
134
135 def run(self, name, fn):
136 name = "%s_%s" % (self.name, name)
137 pipe_cornercases_repeat(self.dut, name, self.mod, self.fmod,
138 self.width, fn, corner_cases, self.fpfn,
139 self.count, self.single_op,
140 opcode=self.opcode)
141
142 def run_cornercases(self):
143 ccs = get_corner_cases(self.mod, self.single_op)
144 vals = repeat(self.dut.num_rows, ccs)
145 tname = "test_fp%s_pipe_fp%d_cornercases" % (self.name, self.width)
146 runfp(self.dut, self.width, tname, self.fmod, self.fpfn, vals=vals,
147 single_op=self.single_op,
148 opcode=self.opcode)
149
150 def run_regressions(self, regressions_fn):
151 vals = repeat(self.dut.num_rows, regressions_fn())
152 #print ("regressions", self.single_op, vals)
153 tname = "test_fp%s_pipe_fp%d_regressions" % (self.name, self.width)
154 runfp(self.dut, self.width, tname, self.fmod, self.fpfn, vals=vals,
155 single_op=self.single_op,
156 opcode=self.opcode)
157
158 def run_random(self):
159 tname = "test_fp%s_pipe_fp%d_rand" % (self.name, self.width)
160 runfp(self.dut, self.width, tname, self.fmod, self.fpfn,
161 single_op=self.single_op,
162 opcode=self.opcode)
163
164
165 def run_pipe_fp(dut, width, name, mod, fmod, regressions, fpfn, count,
166 single_op=False,
167 opcode=None):
168 pc = PipeFPCase(dut, name, mod, fmod, width, fpfn, count, single_op, opcode)
169 if regressions:
170 pc.run_regressions(regressions)
171 pc.run_cornercases()
172 pc.run("rand1", get_rand1)
173 pc.run("n127", get_n127)
174 pc.run("noncan", get_nan_noncan)
175 pc.run("nearlyzero", get_nearly_zero)
176 pc.run("nearlyinf", get_nearly_inf)
177 pc.run("corner_rand", get_corner_rand)
178 pc.run_random()
179