1import os.path
2import itertools
3import Tools
4import random
5import numpy as np
6import scipy
7import scipy.stats
8import math
9
10NBTESTS = 10
11VECDIM = [12,14,20]
12
13def entropyTest(config,nb):
14    DIMS = [3,8,9,12]
15    inputs = []
16    outputs = []
17    dims=[NBTESTS]
18    for i in range(0,NBTESTS):
19       vecDim = DIMS[i % len(DIMS)]
20       dims.append(vecDim)
21       v = np.random.rand(vecDim)
22       v = v / np.sum(v)
23       e = scipy.stats.entropy(v)
24       inputs += list(v)
25       outputs.append(e)
26    inputs = np.array(inputs)
27    outputs = np.array(outputs)
28    dims = np.array(dims)
29    config.writeInput(nb, inputs,"Input")
30    config.writeInputS16(nb, dims,"Dims")
31    config.writeReference(nb, outputs,"RefEntropy")
32
33def logsumexpTest(config,nb):
34    DIMS = [3,8,9,12]
35    inputs = []
36    outputs = []
37    dims=[NBTESTS]
38    for i in range(0,NBTESTS):
39       vecDim = DIMS[i % len(DIMS)]
40       dims.append(vecDim)
41       v = np.random.rand(vecDim)
42       v = v / np.sum(v)
43       e = scipy.special.logsumexp(v)
44       inputs += list(v)
45       outputs.append(e)
46    inputs = np.array(inputs)
47    outputs = np.array(outputs)
48    dims = np.array(dims)
49    config.writeInput(nb, inputs,"Input")
50    config.writeInputS16(nb, dims,"Dims")
51    config.writeReference(nb, outputs,"RefLogSumExp")
52
53def klTest(config,nb):
54    DIMS = [3,8,9,12]
55    inputsA = []
56    inputsB = []
57    outputs = []
58    vecDim = VECDIM[nb % len(VECDIM)]
59    dims=[NBTESTS]
60    for i in range(0,NBTESTS):
61       vecDim = DIMS[i % len(DIMS)]
62       dims.append(vecDim)
63       va = np.random.rand(vecDim)
64       va = va / np.sum(va)
65
66       vb = np.random.rand(vecDim)
67       vb = vb / np.sum(vb)
68
69       e = scipy.stats.entropy(va,vb)
70       inputsA += list(va)
71       inputsB += list(vb)
72       outputs.append(e)
73    inputsA = np.array(inputsA)
74    inputsB = np.array(inputsB)
75    outputs = np.array(outputs)
76    dims = np.array(dims)
77    config.writeInput(nb, inputsA,"InputA")
78    config.writeInput(nb, inputsB,"InputB")
79    config.writeInputS16(nb, dims,"Dims")
80    config.writeReference(nb, outputs,"RefKL")
81
82def logSumExpDotTest(config,nb):
83    DIMS = [3,8,9,12]
84    inputsA = []
85    inputsB = []
86    outputs = []
87    vecDim = VECDIM[nb % len(VECDIM)]
88    dims=[NBTESTS]
89    for i in range(0,NBTESTS):
90       vecDim = DIMS[i % len(DIMS)]
91       dims.append(vecDim)
92       va = np.random.rand(vecDim)
93       va = va / np.sum(va)
94
95       vb = np.random.rand(vecDim)
96       vb = vb / np.sum(vb)
97
98       d = 0.001
99       # It is a proba so must be in [0,1]
100       # But restricted to ]d,1] so that the log exists
101       va = (1-d)*va + d
102       vb = (1-d)*vb + d
103       e = np.log(np.dot(va,vb))
104       va = np.log(va)
105       vb = np.log(vb)
106
107       inputsA += list(va)
108       inputsB += list(vb)
109       outputs.append(e)
110    inputsA = np.array(inputsA)
111    inputsB = np.array(inputsB)
112    outputs = np.array(outputs)
113    dims = np.array(dims)
114    config.writeInput(nb, inputsA,"InputA")
115    config.writeInput(nb, inputsB,"InputB")
116    config.writeInputS16(nb, dims,"Dims")
117    config.writeReference(nb, outputs,"RefLogSumExpDot")
118
119def writeF16OnlyTests(config,nb):
120    entropyTest(config,nb)
121    logsumexpTest(config,nb+1)
122    klTest(config,nb+2)
123    logSumExpDotTest(config,nb+3)
124    return(nb+4)
125
126def writeF32OnlyTests(config,nb):
127    entropyTest(config,nb)
128    logsumexpTest(config,nb+1)
129    klTest(config,nb+2)
130    logSumExpDotTest(config,nb+3)
131    return(nb+4)
132
133def writeF64OnlyTests(config,nb):
134    entropyTest(config,nb)
135    logsumexpTest(config,nb+1)
136    klTest(config,nb+2)
137    logSumExpDotTest(config,nb+3)
138    return(nb+4)
139
140# For index in min and max we need to ensure that the difference between values
141# of the input is big enough to be representable on q31, q15 or q7.
142# Otherwise python will compute an index different from the one
143# computed by CMSIS which is normal but then the CMSIS test will fail.
144
145#vfunc = np.vectorize(squarer)
146
147def floatRound(x,f):
148    return(np.round(x * 2**f)/2**f)
149
150# Min / Max tests
151def generateMaxTests(config,nb,format,data):
152
153
154    indexes=[]
155    maxvals=[]
156
157    nbiters = Tools.loopnb(format,Tools.TAILONLY)
158    index=np.argmax(data[0:nbiters])
159    maxvalue=data[index]
160
161    indexes.append(index)
162    maxvals.append(maxvalue)
163
164    nbiters = Tools.loopnb(format,Tools.BODYONLY)
165    index=np.argmax(data[0:nbiters])
166    maxvalue=data[index]
167
168    indexes.append(index)
169    maxvals.append(maxvalue)
170
171    nbiters = Tools.loopnb(format,Tools.BODYANDTAIL)
172    index=np.argmax(data[0:nbiters])
173    maxvalue=data[index]
174
175    indexes.append(index)
176    maxvals.append(maxvalue)
177
178    if format == 7:
179      # Force max at position 280
180
181      nbiters = 280
182
183      data = np.zeros(nbiters)
184
185      data[nbiters-1] = 0.9
186      data[nbiters-2] = 0.8
187
188      index=np.argmax(data[0:nbiters])
189      maxvalue=data[index]
190
191      indexes.append(index)
192      maxvals.append(maxvalue)
193
194      config.writeInput(nb, data,"InputMaxIndexMax")
195
196    config.writeReference(nb, maxvals,"MaxVals")
197    config.writeInputS16(nb, indexes,"MaxIndexes")
198    return(nb+1)
199
200def generateMinTests(config,nb,format,data):
201
202
203    indexes=[]
204    maxvals=[]
205
206    nbiters = Tools.loopnb(format,Tools.TAILONLY)
207    index=np.argmin(data[0:nbiters])
208    maxvalue=data[index]
209
210    indexes.append(index)
211    maxvals.append(maxvalue)
212
213    nbiters = Tools.loopnb(format,Tools.BODYONLY)
214    index=np.argmin(data[0:nbiters])
215    maxvalue=data[index]
216
217    indexes.append(index)
218    maxvals.append(maxvalue)
219
220    nbiters = Tools.loopnb(format,Tools.BODYANDTAIL)
221    index=np.argmin(data[0:nbiters])
222    maxvalue=data[index]
223
224    indexes.append(index)
225    maxvals.append(maxvalue)
226
227    if format == 7:
228       # Force max at position 280
229       nbiters = 280
230
231       data = 0.9*np.ones(nbiters)
232
233       data[nbiters-1] = 0.0
234       data[nbiters-2] = 0.1
235
236       index=np.argmin(data[0:nbiters])
237       maxvalue=data[index]
238
239       indexes.append(index)
240       maxvals.append(maxvalue)
241
242
243       config.writeInput(nb, data,"InputMinIndexMax")
244    config.writeReference(nb, maxvals,"MinVals")
245    config.writeInputS16(nb, indexes,"MinIndexes")
246    return(nb+1)
247
248# Min/Max Abs Tests
249def generateMaxAbsTests(config,nb,format,data):
250    data = np.abs(data)
251
252    indexes=[]
253    maxvals=[]
254
255    nbiters = Tools.loopnb(format,Tools.TAILONLY)
256    index=np.argmax(data[0:nbiters])
257    maxvalue=data[index]
258
259    indexes.append(index)
260    maxvals.append(maxvalue)
261
262    nbiters = Tools.loopnb(format,Tools.BODYONLY)
263    index=np.argmax(data[0:nbiters])
264    maxvalue=data[index]
265
266    indexes.append(index)
267    maxvals.append(maxvalue)
268
269    nbiters = Tools.loopnb(format,Tools.BODYANDTAIL)
270    index=np.argmax(data[0:nbiters])
271    maxvalue=data[index]
272
273    indexes.append(index)
274    maxvals.append(maxvalue)
275
276    if format == Tools.Q7 or format == Tools.Q15 or format == Tools.Q31:
277       index=np.argmax(data)
278       maxvalue=data[index]
279
280       indexes.append(index)
281       maxvals.append(maxvalue)
282
283    if format == 7:
284      # Force max at position 280 with a new test
285
286      nbiters = 280
287
288      data = np.zeros(nbiters)
289
290      data[nbiters-1] = 0.9
291      data[nbiters-2] = 0.8
292
293      index=np.argmax(data[0:nbiters])
294      maxvalue=data[index]
295
296      indexes.append(index)
297      maxvals.append(maxvalue)
298
299      config.writeInput(nb, data,"InputAbsMaxIndexMax")
300
301
302    config.writeReference(nb, maxvals,"AbsMaxVals")
303    config.writeInputS16(nb, indexes,"AbsMaxIndexes")
304
305    return(nb+1)
306
307def generateMinAbsTests(config,nb,format,data):
308    data = np.abs(data)
309
310    indexes=[]
311    maxvals=[]
312
313    nbiters = Tools.loopnb(format,Tools.TAILONLY)
314    index=np.argmin(data[0:nbiters])
315    maxvalue=data[index]
316
317    indexes.append(index)
318    maxvals.append(maxvalue)
319
320    nbiters = Tools.loopnb(format,Tools.BODYONLY)
321    index=np.argmin(data[0:nbiters])
322    maxvalue=data[index]
323
324    indexes.append(index)
325    maxvals.append(maxvalue)
326
327    nbiters = Tools.loopnb(format,Tools.BODYANDTAIL)
328    index=np.argmin(data[0:nbiters])
329    maxvalue=data[index]
330
331    indexes.append(index)
332    maxvals.append(maxvalue)
333
334    if format == 7:
335       # Force max at position 280
336       nbiters = 280
337
338       data = 0.9*np.ones(nbiters)
339
340       data[nbiters-1] = 0.0
341       data[nbiters-2] = 0.1
342
343       index=np.argmin(data[0:nbiters])
344       maxvalue=data[index]
345
346       indexes.append(index)
347       maxvals.append(maxvalue)
348
349
350       config.writeInput(nb, data,"InputAbsMinIndexMax")
351    config.writeReference(nb, maxvals,"AbsMinVals")
352    config.writeInputS16(nb, indexes,"AbsMinIndexes")
353    return(nb+1)
354
355def averageTest(format,data):
356   return(np.average(data))
357
358def powerTest(format,data):
359   if format == 31:
360       return(np.dot(data,data) / 2**15) # CMSIS is 2.28 format
361   elif format == 15:
362       return(np.dot(data,data) / 2**33) # CMSIS is 34.30 format
363   elif format == 7:
364       return(np.dot(data,data) / 2**17) # CMSIS is 18.14 format
365   else:
366       return(np.dot(data,data))
367
368def mseTest(format,data1,data2):
369   nb = len(data1)
370   err = data1 - data2
371   return(np.dot(err,err) / nb)
372
373def rmsTest(format,data):
374   return(math.sqrt(np.dot(data,data)/data.size))
375
376def stdTest(format,data):
377   return(np.std(data,ddof=1))
378
379def varTest(format,data):
380   return(np.var(data,ddof=1))
381
382def generateFuncTests(config,nb,format,data,func,name):
383
384    funcvals=[]
385
386    nbiters = Tools.loopnb(format,Tools.TAILONLY)
387    funcvalue=func(format,data[0:nbiters])
388    funcvals.append(funcvalue)
389
390    nbiters = Tools.loopnb(format,Tools.BODYONLY)
391    funcvalue=func(format,data[0:nbiters])
392    funcvals.append(funcvalue)
393
394    nbiters = Tools.loopnb(format,Tools.BODYANDTAIL)
395    funcvalue=func(format,data[0:nbiters])
396    funcvals.append(funcvalue)
397
398    nbiters = 100
399    funcvalue=func(format,data[0:nbiters])
400    funcvals.append(funcvalue)
401
402    config.writeReference(nb, funcvals,name)
403    return(nb+1)
404
405def generateOperatorTests(config,nb,format,data1,data2,func,name):
406
407    funcvals=[]
408
409    nbiters = Tools.loopnb(format,Tools.TAILONLY)
410    funcvalue=func(format,data1[0:nbiters],data2[0:nbiters])
411    funcvals.append(funcvalue)
412
413    nbiters = Tools.loopnb(format,Tools.BODYONLY)
414    funcvalue=func(format,data1[0:nbiters],data2[0:nbiters])
415    funcvals.append(funcvalue)
416
417    nbiters = Tools.loopnb(format,Tools.BODYANDTAIL)
418    funcvalue=func(format,data1[0:nbiters],data2[0:nbiters])
419    funcvals.append(funcvalue)
420
421    nbiters = 100
422    funcvalue=func(format,data1[0:nbiters],data2[0:nbiters])
423    funcvals.append(funcvalue)
424
425    config.writeReference(nb, funcvals,name)
426    return(nb+1)
427
428def generatePowerTests(config,nb,format,data):
429
430    funcvals=[]
431
432    nbiters = Tools.loopnb(format,Tools.TAILONLY)
433    funcvalue=powerTest(format,data[0:nbiters])
434    funcvals.append(funcvalue)
435
436    nbiters = Tools.loopnb(format,Tools.BODYONLY)
437    funcvalue=powerTest(format,data[0:nbiters])
438    funcvals.append(funcvalue)
439
440    nbiters = Tools.loopnb(format,Tools.BODYANDTAIL)
441    funcvalue=powerTest(format,data[0:nbiters])
442    funcvals.append(funcvalue)
443
444    if format==31 or format==15:
445      config.writeReferenceQ63(nb, funcvals,"PowerVals")
446    elif format==7:
447      config.writeReferenceQ31(nb, funcvals,"PowerVals")
448    else:
449      config.writeReference(nb, funcvals,"PowerVals")
450    return(nb+1)
451
452def writeTests(config,nb,format):
453    NBSAMPLES = 300
454    data1=np.random.randn(NBSAMPLES)
455    data2=np.random.randn(NBSAMPLES)
456
457    data1 = Tools.normalize(data1)
458    data2 = np.abs(data1)
459
460    # Force quantization so that computation of indexes
461    # in min/max is coherent between Python and CMSIS.
462    # Otherwise there will be normal differences and the test
463    # will be displayed as failed.
464    if format==31:
465       data1=floatRound(data1,31)
466
467    if format==15:
468       data1=floatRound(data1,15)
469
470    if format==7:
471       data1=floatRound(data1,7)
472
473    config.writeInput(1, data1,"Input")
474    config.writeInput(2, data2,"Input")
475
476    nb=generateMaxTests(config,nb,format,data1)
477    nb=generateFuncTests(config,nb,format,data2,averageTest,"MeanVals")
478    nb=generateMinTests(config,nb,format,data1)
479    nb=generatePowerTests(config,nb,format,data1)
480    nb=generateFuncTests(config,nb,format,data1,rmsTest,"RmsVals")
481    nb=generateFuncTests(config,nb,format,data1,stdTest,"StdVals")
482    nb=generateFuncTests(config,nb,format,data1,varTest,"VarVals")
483    return(nb)
484
485# We don't want to change ID number of existing tests.
486# So new tests have to be added after existing ones
487def writeNewsTests(config,nb,format):
488    NBSAMPLES = 300
489
490    data1=np.random.randn(NBSAMPLES)
491    data1 = Tools.normalize(data1)
492
493    data2=np.random.randn(NBSAMPLES)
494    data2 = Tools.normalize(data2)
495
496    # Add max negative value
497    # to test saturation
498    if format == Tools.Q7:
499        data1 = np.hstack((data1,np.array([-1.0])))
500
501    if format == Tools.Q15:
502        data1 = np.hstack((data1,np.array([-1.0])))
503
504    if format == Tools.Q31:
505        data1 = np.hstack((data1,np.array([-1.0])))
506
507    config.writeInput(1, data1,"InputNew")
508
509    nb=generateMaxAbsTests(config,nb,format,data1)
510    nb=generateMinAbsTests(config,nb,format,data1)
511
512    config.writeInput(2, data2,"InputNew")
513    nb=generateOperatorTests(config,nb,format,data1,data2,mseTest,"MSEVals")
514
515    return(nb)
516
517def writeAccumulateTests(config,nb,format):
518    NBSAMPLES = 300
519    data1=np.random.randn(NBSAMPLES)
520
521    # First value is the number of tests
522    # Other values are the number of samples in each test
523    nbsamples = [4]
524    nbiters = Tools.loopnb(format,Tools.TAILONLY)
525    nbsamples.append(nbiters)
526
527    nbiters = Tools.loopnb(format,Tools.BODYONLY)
528    nbsamples.append(nbiters)
529
530    nbiters = Tools.loopnb(format,Tools.BODYANDTAIL)
531    nbsamples.append(nbiters)
532
533    nbsamples.append(NBSAMPLES)
534    ref=[]
535
536
537    for nb in nbsamples[1:]:
538        t = np.sum(data1[:nb])
539        ref.append(t)
540
541    config.writeInput(1, data1,"InputAccumulate")
542    config.writeInputS16(1, nbsamples,"InputAccumulateConfig")
543    config.writeReference(1, ref,"RefAccumulate")
544
545    return(nb+1)
546
547
548
549def generateBenchmark(config,format):
550    NBSAMPLES = 256
551    data1=np.random.randn(NBSAMPLES)
552    data2=np.random.randn(NBSAMPLES)
553
554    data1 = Tools.normalize(data1)
555    data2 = np.abs(data1)
556
557    if format==31:
558       data1=floatRound(data1,31)
559
560    if format==15:
561       data1=floatRound(data1,15)
562
563    if format==7:
564       data1=floatRound(data1,7)
565
566    config.writeInput(1, data1,"InputBench")
567    config.writeInput(2, data2,"InputBench")
568
569
570def generatePatterns():
571    PATTERNDIR = os.path.join("Patterns","DSP","Stats","Stats")
572    PARAMDIR = os.path.join("Parameters","DSP","Stats","Stats")
573
574    configf64=Tools.Config(PATTERNDIR,PARAMDIR,"f64")
575    configf32=Tools.Config(PATTERNDIR,PARAMDIR,"f32")
576    configf16=Tools.Config(PATTERNDIR,PARAMDIR,"f16")
577    configq31=Tools.Config(PATTERNDIR,PARAMDIR,"q31")
578    configq15=Tools.Config(PATTERNDIR,PARAMDIR,"q15")
579    configq7 =Tools.Config(PATTERNDIR,PARAMDIR,"q7")
580
581    configf64.setOverwrite(False)
582    configf32.setOverwrite(False)
583    configf16.setOverwrite(False)
584    configq31.setOverwrite(False)
585    configq15.setOverwrite(False)
586    configq7.setOverwrite(False)
587
588    nb=writeTests(configf32,1,0)
589    nb=writeF32OnlyTests(configf32,22)
590    nb=writeNewsTests(configf32,nb,Tools.F32)
591    nb=writeAccumulateTests(configf32,nb,Tools.F32)
592
593    nb=writeTests(configf64,1,Tools.F64)
594    nb=writeF64OnlyTests(configf64,22)
595    nb=writeNewsTests(configf64,nb,Tools.F64)
596    nb=writeAccumulateTests(configf64,nb,Tools.F64)
597
598    nb=writeTests(configq31,1,31)
599    nb=writeNewsTests(configq31,nb,Tools.Q31)
600
601    nb=writeTests(configq15,1,15)
602    nb=writeNewsTests(configq15,nb,Tools.Q15)
603
604    nb=writeTests(configq7,1,7)
605    nb=writeNewsTests(configq7,nb,Tools.Q7)
606
607    nb=writeTests(configf16,1,16)
608    nb=writeF16OnlyTests(configf16,22)
609    nb=writeNewsTests(configf16,nb,Tools.F16)
610    nb=writeAccumulateTests(configf16,nb,Tools.F16)
611
612    generateBenchmark(configf64, Tools.F64)
613    generateBenchmark(configf32, Tools.F32)
614    generateBenchmark(configf16, Tools.F16)
615    generateBenchmark(configq31, Tools.Q31)
616    generateBenchmark(configq15, Tools.Q15)
617    generateBenchmark(configq7, Tools.Q7)
618
619if __name__ == '__main__':
620  generatePatterns()
621