blob: bdf0be4f1d90aa20e8aff4f014eba9e2564ab15a [file] [log] [blame]
Daniel Dunbara83fb862009-01-15 04:24:17 +00001#!/usr/bin/python
2
3from pprint import pprint
4import random, atexit, time
5from random import randrange
6
7from Enumeration import *
8from TypeGen import *
9
10####
11
12class TypePrinter:
13 def __init__(self, output, outputHeader=None,
14 outputTests=None, outputDriver=None,
15 headerName=None, info=None):
16 self.output = output
17 self.outputHeader = outputHeader
18 self.outputTests = outputTests
19 self.outputDriver = outputDriver
20 self.writeBody = outputHeader or outputTests or outputDriver
21 self.types = {}
22 self.testValues = {}
23 self.testReturnValues = {}
Daniel Dunbar5ce61572009-01-28 02:01:23 +000024 self.layoutTests = []
Daniel Dunbara83fb862009-01-15 04:24:17 +000025
26 if info:
27 for f in (self.output,self.outputHeader,self.outputTests,self.outputDriver):
28 if f:
29 print >>f,info
30
31 if self.writeBody:
32 print >>self.output, '#include <stdio.h>\n'
33 if self.outputTests:
34 print >>self.outputTests, '#include <stdio.h>\n'
35
36 if headerName:
37 for f in (self.output,self.outputTests,self.outputDriver):
38 if f is not None:
39 print >>f, '#include "%s"\n'%(headerName,)
40
41 if self.outputDriver:
42 print >>self.outputDriver, 'int main(int argc, char **argv) {'
43
44 def finish(self):
Daniel Dunbar5ce61572009-01-28 02:01:23 +000045 if self.layoutTests:
46 print >>self.output, 'int main(int argc, char **argv) {'
47 for f in self.layoutTests:
48 print >>self.output, ' %s();' % f
49 print >>self.output, ' return 0;'
50 print >>self.output, '}'
51
Daniel Dunbara83fb862009-01-15 04:24:17 +000052 if self.outputDriver:
53 print >>self.outputDriver, ' return 0;'
Daniel Dunbar5ce61572009-01-28 02:01:23 +000054 print >>self.outputDriver, '}'
Daniel Dunbara83fb862009-01-15 04:24:17 +000055
56 def getTypeName(self, T):
57 if isinstance(T,BuiltinType):
58 return T.name
59 name = self.types.get(T)
60 if name is None:
61 name = 'T%d'%(len(self.types),)
62 # Reserve slot
63 self.types[T] = None
64 if self.outputHeader:
65 print >>self.outputHeader,T.getTypedefDef(name, self)
66 else:
67 print >>self.output,T.getTypedefDef(name, self)
68 if self.outputTests:
69 print >>self.outputTests,T.getTypedefDef(name, self)
70 self.types[T] = name
71 return name
72
Daniel Dunbar5ce61572009-01-28 02:01:23 +000073 def writeLayoutTest(self, i, ty):
74 tyName = self.getTypeName(ty)
75 tyNameClean = tyName.replace(' ','_').replace('*','star')
76 fnName = 'test_%s' % tyNameClean
77
78 print >>self.output,'void %s(void) {' % fnName
79 self.printSizeOfType(' %s'%fnName, tyName, ty, self.output)
80 self.printAlignOfType(' %s'%fnName, tyName, ty, self.output)
81 self.printOffsetsOfType(' %s'%fnName, tyName, ty, self.output)
82 print >>self.output,'}'
83 print >>self.output
84
85 self.layoutTests.append(fnName)
86
Daniel Dunbara83fb862009-01-15 04:24:17 +000087 def writeFunction(self, i, FT):
88 args = ', '.join(['%s arg%d'%(self.getTypeName(t),i) for i,t in enumerate(FT.argTypes)])
89 if not args:
90 args = 'void'
91
92 if FT.returnType is None:
93 retvalName = None
94 retvalTypeName = 'void'
95 else:
96 retvalTypeName = self.getTypeName(FT.returnType)
97 if self.writeBody or self.outputTests:
98 retvalName = self.getTestReturnValue(FT.returnType)
99
100 fnName = 'fn%d'%(FT.index,)
101 if self.outputHeader:
102 print >>self.outputHeader,'%s %s(%s);'%(retvalTypeName, fnName, args)
103 elif self.outputTests:
104 print >>self.outputTests,'%s %s(%s);'%(retvalTypeName, fnName, args)
105
106 print >>self.output,'%s %s(%s)'%(retvalTypeName, fnName, args),
107 if self.writeBody:
108 print >>self.output, '{'
109
110 for i,t in enumerate(FT.argTypes):
111 self.printValueOfType(' %s'%fnName, 'arg%d'%i, t)
112
113 if retvalName is not None:
114 print >>self.output, ' return %s;'%(retvalName,)
115 print >>self.output, '}'
116 else:
117 print >>self.output, '{}'
118 print >>self.output
119
120 if self.outputDriver:
121 print >>self.outputDriver, ' { extern void test_%s(void); test_%s(); }\n'%(fnName,fnName,)
122
123 if self.outputTests:
124 if self.outputHeader:
125 print >>self.outputHeader, 'void test_%s(void);'%(fnName,)
126
127 if retvalName is None:
128 retvalTests = None
129 else:
130 retvalTests = self.getTestValuesArray(FT.returnType)
131 tests = map(self.getTestValuesArray, FT.argTypes)
132 print >>self.outputTests, 'void test_%s(void) {'%(fnName,)
133
134 if retvalTests is not None:
135 print >>self.outputTests, ' printf("%s: testing return.\\n");'%(fnName,)
136 print >>self.outputTests, ' for (int i=0; i<%d; ++i) {'%(retvalTests[1],)
137 args = ', '.join(['%s[%d]'%(t,randrange(l)) for t,l in tests])
138 print >>self.outputTests, ' %s RV;'%(retvalTypeName,)
139 print >>self.outputTests, ' %s = %s[i];'%(retvalName, retvalTests[0])
140 print >>self.outputTests, ' RV = %s(%s);'%(fnName, args)
141 self.printValueOfType(' %s_RV'%fnName, 'RV', FT.returnType, output=self.outputTests, indent=4)
142 print >>self.outputTests, ' }'
143
144 if tests:
145 print >>self.outputTests, ' printf("%s: testing arguments.\\n");'%(fnName,)
146 for i,(array,length) in enumerate(tests):
147 for j in range(length):
148 args = ['%s[%d]'%(t,randrange(l)) for t,l in tests]
149 args[i] = '%s[%d]'%(array,j)
150 print >>self.outputTests, ' %s(%s);'%(fnName, ', '.join(args),)
151 print >>self.outputTests, '}'
152
153 def getTestReturnValue(self, type):
154 typeName = self.getTypeName(type)
155 info = self.testReturnValues.get(typeName)
156 if info is None:
157 name = '%s_retval'%(typeName.replace(' ','_').replace('*','star'),)
158 print >>self.output, '%s %s;'%(typeName,name)
159 if self.outputHeader:
160 print >>self.outputHeader, 'extern %s %s;'%(typeName,name)
161 elif self.outputTests:
162 print >>self.outputTests, 'extern %s %s;'%(typeName,name)
163 info = self.testReturnValues[typeName] = name
164 return info
165
166 def getTestValuesArray(self, type):
167 typeName = self.getTypeName(type)
168 info = self.testValues.get(typeName)
169 if info is None:
170 name = '%s_values'%(typeName.replace(' ','_').replace('*','star'),)
171 print >>self.outputTests, 'static %s %s[] = {'%(typeName,name)
172 length = 0
173 for item in self.getTestValues(type):
174 print >>self.outputTests, '\t%s,'%(item,)
175 length += 1
176 print >>self.outputTests,'};'
177 info = self.testValues[typeName] = (name,length)
178 return info
179
180 def getTestValues(self, t):
181 if isinstance(t, BuiltinType):
182 if t.name=='float':
183 for i in ['0.0','-1.0','1.0']:
184 yield i+'f'
185 elif t.name=='double':
186 for i in ['0.0','-1.0','1.0']:
187 yield i
188 elif t.name in ('void *'):
189 yield '(void*) 0'
190 yield '(void*) -1'
191 else:
192 yield '(%s) 0'%(t.name,)
193 yield '(%s) -1'%(t.name,)
194 yield '(%s) 1'%(t.name,)
195 elif isinstance(t, RecordType):
Daniel Dunbara83fb862009-01-15 04:24:17 +0000196 if not t.fields:
197 yield '{ }'
Daniel Dunbar900ed552009-01-29 07:36:46 +0000198 return
199 # FIXME: Use designated initializers to access non-first
200 # fields of unions.
201 if t.isUnion:
202 for v in self.getTestValues(t.fields[0]):
203 yield '{ %s }' % v
204 return
205 fieldValues = [list(self.getTestValues(f)) for f in t.fields]
Daniel Dunbara83fb862009-01-15 04:24:17 +0000206 for i,values in enumerate(fieldValues):
207 for v in values:
208 elements = map(random.choice,fieldValues)
209 elements[i] = v
210 yield '{ %s }'%(', '.join(elements))
211 elif isinstance(t, ComplexType):
212 for t in self.getTestValues(t.elementType):
Daniel Dunbar550faa32009-01-26 19:05:20 +0000213 yield '%s + %s * 1i'%(t,t)
214 elif isinstance(t, ArrayType):
Daniel Dunbara83fb862009-01-15 04:24:17 +0000215 values = list(self.getTestValues(t.elementType))
216 if not values:
217 yield '{ }'
Daniel Dunbar550faa32009-01-26 19:05:20 +0000218 for i in range(t.numElements):
Daniel Dunbara83fb862009-01-15 04:24:17 +0000219 for v in values:
Daniel Dunbar550faa32009-01-26 19:05:20 +0000220 elements = [random.choice(values) for i in range(t.numElements)]
Daniel Dunbara83fb862009-01-15 04:24:17 +0000221 elements[i] = v
222 yield '{ %s }'%(', '.join(elements))
223 else:
224 raise NotImplementedError,'Cannot make tests values of type: "%s"'%(t,)
225
Daniel Dunbar5ce61572009-01-28 02:01:23 +0000226 def printSizeOfType(self, prefix, name, t, output=None, indent=2):
227 print >>output, '%*sprintf("%s: sizeof(%s) = %%ld\\n", sizeof(%s));'%(indent, '', prefix, name, name)
228 def printAlignOfType(self, prefix, name, t, output=None, indent=2):
229 print >>output, '%*sprintf("%s: __alignof__(%s) = %%ld\\n", __alignof__(%s));'%(indent, '', prefix, name, name)
230 def printOffsetsOfType(self, prefix, name, t, output=None, indent=2):
231 if isinstance(t, RecordType):
232 for i,f in enumerate(t.fields):
233 fname = 'field%d' % i
234 print >>output, '%*sprintf("%s: __builtin_offsetof(%s, %s) = %%ld\\n", __builtin_offsetof(%s, %s));'%(indent, '', prefix, name, fname, name, fname)
235
Daniel Dunbara83fb862009-01-15 04:24:17 +0000236 def printValueOfType(self, prefix, name, t, output=None, indent=2):
237 if output is None:
238 output = self.output
239 if isinstance(t, BuiltinType):
240 if t.name.endswith('long long'):
241 code = 'lld'
242 elif t.name.endswith('long'):
243 code = 'ld'
244 elif t.name.split(' ')[-1] in ('_Bool','char','short','int'):
245 code = 'd'
246 elif t.name in ('float','double'):
247 code = 'f'
248 elif t.name == 'long double':
249 code = 'Lf'
250 else:
251 code = 'p'
252 print >>output, '%*sprintf("%s: %s = %%%s\\n", %s);'%(indent, '', prefix, name, code, name)
253 elif isinstance(t, RecordType):
254 if not t.fields:
255 print >>output, '%*sprintf("%s: %s (empty)\\n");'%(indent, '', prefix, name)
256 for i,f in enumerate(t.fields):
257 fname = '%s.field%d'%(name,i)
258 self.printValueOfType(prefix, fname, f, output=output, indent=indent)
259 elif isinstance(t, ComplexType):
260 self.printValueOfType(prefix, '(__real %s)'%name, t.elementType, output=output,indent=indent)
261 self.printValueOfType(prefix, '(__imag %s)'%name, t.elementType, output=output,indent=indent)
Daniel Dunbar550faa32009-01-26 19:05:20 +0000262 elif isinstance(t, ArrayType):
263 for i in range(t.numElements):
264 # Access in this fashion as a hackish way to portably
265 # access vectors.
Daniel Dunbare61e95f2009-01-29 08:48:06 +0000266 if t.isVector:
267 self.printValueOfType(prefix, '((%s*) &%s)[%d]'%(t.elementType,name,i), t.elementType, output=output,indent=indent)
268 else:
269 self.printValueOfType(prefix, '%s[%d]'%(name,i), t.elementType, output=output,indent=indent)
Daniel Dunbara83fb862009-01-15 04:24:17 +0000270 else:
271 raise NotImplementedError,'Cannot print value of type: "%s"'%(t,)
272
273import sys
274
275def main():
276 from optparse import OptionParser, OptionGroup
277 parser = OptionParser("%prog [options] {indices}")
278 parser.add_option("", "--mode", dest="mode",
279 help="autogeneration mode (random or linear) [default %default]",
280 type='choice', choices=('random','linear'), default='linear')
281 parser.add_option("", "--count", dest="count",
282 help="autogenerate COUNT functions according to MODE",
283 type=int, default=0)
284 parser.add_option("", "--min", dest="minIndex", metavar="N",
285 help="start autogeneration with the Nth function type [default %default]",
286 type=int, default=0)
287 parser.add_option("", "--max", dest="maxIndex", metavar="N",
288 help="maximum index for random autogeneration [default %default]",
289 type=int, default=10000000)
290 parser.add_option("", "--seed", dest="seed",
291 help="random number generator seed [default %default]",
292 type=int, default=1)
293 parser.add_option("", "--use-random-seed", dest="useRandomSeed",
294 help="use random value for initial random number generator seed",
295 action='store_true', default=False)
296 parser.add_option("-o", "--output", dest="output", metavar="FILE",
297 help="write output to FILE [default %default]",
298 type=str, default='-')
299 parser.add_option("-O", "--output-header", dest="outputHeader", metavar="FILE",
300 help="write header file for output to FILE [default %default]",
301 type=str, default=None)
302 parser.add_option("-T", "--output-tests", dest="outputTests", metavar="FILE",
303 help="write function tests to FILE [default %default]",
304 type=str, default=None)
305 parser.add_option("-D", "--output-driver", dest="outputDriver", metavar="FILE",
306 help="write test driver to FILE [default %default]",
307 type=str, default=None)
Daniel Dunbar5ce61572009-01-28 02:01:23 +0000308 parser.add_option("", "--test-layout", dest="testLayout", metavar="FILE",
309 help="test structure layout",
310 action='store_true', default=False)
Daniel Dunbara83fb862009-01-15 04:24:17 +0000311
312 group = OptionGroup(parser, "Type Enumeration Options")
313 # Builtins - Ints
314 group.add_option("", "--no-char", dest="useChar",
315 help="do not generate char types",
316 action="store_false", default=True)
317 group.add_option("", "--no-short", dest="useShort",
318 help="do not generate short types",
319 action="store_false", default=True)
320 group.add_option("", "--no-int", dest="useInt",
321 help="do not generate int types",
322 action="store_false", default=True)
323 group.add_option("", "--no-long", dest="useLong",
324 help="do not generate long types",
325 action="store_false", default=True)
326 group.add_option("", "--no-long-long", dest="useLongLong",
327 help="do not generate long long types",
328 action="store_false", default=True)
329 group.add_option("", "--no-unsigned", dest="useUnsigned",
330 help="do not generate unsigned integer types",
331 action="store_false", default=True)
332
333 # Other builtins
334 group.add_option("", "--no-bool", dest="useBool",
335 help="do not generate bool types",
336 action="store_false", default=True)
337 group.add_option("", "--no-float", dest="useFloat",
338 help="do not generate float types",
339 action="store_false", default=True)
340 group.add_option("", "--no-double", dest="useDouble",
341 help="do not generate double types",
342 action="store_false", default=True)
343 group.add_option("", "--no-long-double", dest="useLongDouble",
344 help="do not generate long double types",
345 action="store_false", default=True)
346 group.add_option("", "--no-void-pointer", dest="useVoidPointer",
347 help="do not generate void* types",
348 action="store_false", default=True)
349
350 # Derived types
351 group.add_option("", "--no-array", dest="useArray",
352 help="do not generate record types",
353 action="store_false", default=True)
354 group.add_option("", "--no-complex", dest="useComplex",
355 help="do not generate complex types",
356 action="store_false", default=True)
357 group.add_option("", "--no-record", dest="useRecord",
358 help="do not generate record types",
359 action="store_false", default=True)
360 group.add_option("", "--no-union", dest="recordUseUnion",
361 help="do not generate union types",
362 action="store_false", default=True)
363 group.add_option("", "--no-vector", dest="useVector",
364 help="do not generate vector types",
365 action="store_false", default=True)
366
367 # Tuning
368 group.add_option("", "--no-function-return", dest="functionUseReturn",
369 help="do not generate return types for functions",
370 action="store_false", default=True)
371 group.add_option("", "--vector-sizes", dest="vectorSizes",
372 help="comma separated list of sizes for vectors [default %default]",
Daniel Dunbar5ce61572009-01-28 02:01:23 +0000373 action="store", type=str, default='8,16', metavar="N")
Daniel Dunbara83fb862009-01-15 04:24:17 +0000374
375 group.add_option("", "--max-args", dest="functionMaxArgs",
376 help="maximum number of arguments per function [default %default]",
377 action="store", type=int, default=4, metavar="N")
378 group.add_option("", "--max-array", dest="arrayMaxSize",
379 help="maximum array size [default %default]",
380 action="store", type=int, default=4, metavar="N")
381 group.add_option("", "--max-record", dest="recordMaxSize",
382 help="maximum number of fields per record [default %default]",
383 action="store", type=int, default=4, metavar="N")
384 group.add_option("", "--max-record-depth", dest="recordMaxDepth",
385 help="maximum nested structure depth [default %default]",
386 action="store", type=int, default=None, metavar="N")
387 parser.add_option_group(group)
388 (opts, args) = parser.parse_args()
389
390 if not opts.useRandomSeed:
391 random.seed(opts.seed)
392
393 # Contruct type generator
394 builtins = []
395 ints = []
Daniel Dunbar550faa32009-01-26 19:05:20 +0000396 if opts.useChar: ints.append(('char',1))
397 if opts.useShort: ints.append(('short',2))
398 if opts.useInt: ints.append(('int',4))
399 # FIXME: Wrong size.
400 if opts.useLong: ints.append(('long',4))
401 if opts.useLongLong: ints.append(('long long',8))
Daniel Dunbara83fb862009-01-15 04:24:17 +0000402 if opts.useUnsigned:
Daniel Dunbar550faa32009-01-26 19:05:20 +0000403 ints = ([('unsigned %s'%i,s) for i,s in ints] +
404 [('signed %s'%i,s) for i,s in ints])
Daniel Dunbara83fb862009-01-15 04:24:17 +0000405 builtins.extend(ints)
406
Daniel Dunbar550faa32009-01-26 19:05:20 +0000407 if opts.useBool: builtins.append(('_Bool',1))
408 if opts.useFloat: builtins.append(('float',4))
409 if opts.useDouble: builtins.append(('double',8))
410 if opts.useLongDouble: builtins.append(('long double',16))
411 # FIXME: Wrong size.
412 if opts.useVoidPointer: builtins.append(('void*',4))
Daniel Dunbara83fb862009-01-15 04:24:17 +0000413
Daniel Dunbar550faa32009-01-26 19:05:20 +0000414 btg = FixedTypeGenerator([BuiltinType(n,s) for n,s in builtins])
415 sbtg = FixedTypeGenerator([BuiltinType('char',1),
416 BuiltinType('int',4),
Daniel Dunbar5ce61572009-01-28 02:01:23 +0000417 BuiltinType('float',4),
418 BuiltinType('double',8)])
Daniel Dunbara83fb862009-01-15 04:24:17 +0000419
420 atg = AnyTypeGenerator()
421 artg = AnyTypeGenerator()
422 def makeGenerator(atg, subgen, useRecord, useArray):
423 atg.addGenerator(btg)
424 if useRecord and opts.useRecord:
425 assert subgen
426 atg.addGenerator(RecordTypeGenerator(subgen, opts.recordUseUnion,
427 opts.recordMaxSize))
428 if opts.useComplex:
429 # FIXME: Allow overriding builtins here
430 atg.addGenerator(ComplexTypeGenerator(sbtg))
431 if useArray and opts.useArray:
432 assert subgen
433 atg.addGenerator(ArrayTypeGenerator(subgen, opts.arrayMaxSize))
434 if opts.useVector:
435 atg.addGenerator(VectorTypeGenerator(sbtg,
436 map(int, opts.vectorSizes.split(','))))
437
438
439 if opts.recordMaxDepth is None:
440 # Fully recursive, just avoid top-level arrays.
441 subTG = AnyTypeGenerator()
442 atg = AnyTypeGenerator()
443 makeGenerator(subTG, atg, True, True)
444 makeGenerator(atg, subTG, True, False)
445 else:
446 # Make a chain of type generators, each builds smaller
447 # structures.
448 base = AnyTypeGenerator()
449 makeGenerator(base, None, False, False)
450 for i in range(opts.recordMaxDepth):
451 n = AnyTypeGenerator()
452 makeGenerator(n, base, True, True)
453 base = n
454 atg = AnyTypeGenerator()
455 makeGenerator(atg, base, True, False)
456
Daniel Dunbar5ce61572009-01-28 02:01:23 +0000457 if opts.testLayout:
458 ftg = atg
459 else:
460 ftg = FunctionTypeGenerator(atg, opts.functionUseReturn, opts.functionMaxArgs)
Daniel Dunbara83fb862009-01-15 04:24:17 +0000461
462 # Override max,min,count if finite
463 if opts.maxIndex is None:
464 if ftg.cardinality is aleph0:
465 opts.maxIndex = 10000000
466 else:
467 opts.maxIndex = ftg.cardinality
468 opts.maxIndex = min(opts.maxIndex, ftg.cardinality)
469 opts.minIndex = max(0,min(opts.maxIndex-1, opts.minIndex))
470 if not opts.mode=='random':
471 opts.count = min(opts.count, opts.maxIndex-opts.minIndex)
472
473 if opts.output=='-':
474 output = sys.stdout
475 else:
476 output = open(opts.output,'w')
477 atexit.register(lambda: output.close())
478
479 outputHeader = None
480 if opts.outputHeader:
481 outputHeader = open(opts.outputHeader,'w')
482 atexit.register(lambda: outputHeader.close())
483
484 outputTests = None
485 if opts.outputTests:
486 outputTests = open(opts.outputTests,'w')
487 atexit.register(lambda: outputTests.close())
488
489 outputDriver = None
490 if opts.outputDriver:
491 outputDriver = open(opts.outputDriver,'w')
492 atexit.register(lambda: outputDriver.close())
493
494 info = ''
495 info += '// %s\n'%(' '.join(sys.argv),)
496 info += '// Generated: %s\n'%(time.strftime('%Y-%m-%d %H:%M'),)
497 info += '// Cardinality of function generator: %s\n'%(ftg.cardinality,)
498 info += '// Cardinality of type generator: %s\n'%(atg.cardinality,)
Daniel Dunbar5ce61572009-01-28 02:01:23 +0000499
500 if opts.testLayout:
501 info += '\n#include <stdio.h>'
Daniel Dunbara83fb862009-01-15 04:24:17 +0000502
503 P = TypePrinter(output,
504 outputHeader=outputHeader,
505 outputTests=outputTests,
506 outputDriver=outputDriver,
Daniel Dunbar5ce61572009-01-28 02:01:23 +0000507 headerName=opts.outputHeader,
Daniel Dunbara83fb862009-01-15 04:24:17 +0000508 info=info)
509
510 def write(N):
Daniel Dunbar5ce61572009-01-28 02:01:23 +0000511 try:
Daniel Dunbara83fb862009-01-15 04:24:17 +0000512 FT = ftg.get(N)
513 except RuntimeError,e:
514 if e.args[0]=='maximum recursion depth exceeded':
515 print >>sys.stderr,'WARNING: Skipped %d, recursion limit exceeded (bad arguments?)'%(N,)
516 return
517 raise
Daniel Dunbar5ce61572009-01-28 02:01:23 +0000518 if opts.testLayout:
519 P.writeLayoutTest(N, FT)
520 else:
521 P.writeFunction(N, FT)
Daniel Dunbara83fb862009-01-15 04:24:17 +0000522
523 if args:
524 [write(int(a)) for a in args]
525
526 for i in range(opts.count):
527 if opts.mode=='linear':
528 index = opts.minIndex + i
529 else:
530 index = opts.minIndex + int((opts.maxIndex-opts.minIndex) * random.random())
531 write(index)
532
533 P.finish()
534
535if __name__=='__main__':
536 main()
537