@@ -253,6 +253,14 @@ def get_length(self) -> int:
253
253
" but none was given when get_length was called." )
254
254
return self .rand_length_val
255
255
256
+ def is_list (self ) -> bool :
257
+ '''
258
+ Returns ``True`` if this is a list variable.
259
+
260
+ :return: ``True`` if this is a list variable, otherwise ``False``.
261
+ '''
262
+ return self .length is not None or self .rand_length is not None
263
+
256
264
def set_rand_length (self , length : int ) -> None :
257
265
'''
258
266
Function to set the random length.
@@ -282,31 +290,48 @@ def _get_random(self) -> random.Random:
282
290
return random
283
291
return self ._random
284
292
285
- def get_domain_size (self ) -> int :
293
+ def get_domain_size (self , possible_lengths : Optional [ List [ int ]] = None ) -> int :
286
294
'''
287
295
Return total domain size, accounting for length of this random variable.
288
296
297
+ :param possible_lengths: Optional, when there is more than one possiblity
298
+ for the value of the random length, specifies a list of the
299
+ possibilities.
289
300
:return: domain size, integer.
290
301
'''
291
302
if self .domain is None :
292
303
# If there's no domain, it means we can't estimate the complexity
293
304
# of this variable. Return 1.
294
305
return 1
295
306
else :
296
- length = self .get_length ()
297
- if length is None :
298
- # length is None implies a scalar variable.
299
- return len (self .domain )
300
- elif length == 0 :
301
- # This is a zero-length list, adding no complexity.
302
- return 1
303
- elif length == 1 :
304
- return len (self .domain )
307
+ # possible_lengths is used when the variable has a random
308
+ # length and that length is not yet fully determined.
309
+ if possible_lengths is None :
310
+ # Normal, fixed length of some description.
311
+ length = self .get_length ()
312
+ if length is None :
313
+ # length is None implies a scalar variable.
314
+ return len (self .domain )
315
+ elif length == 0 :
316
+ # This is a zero-length list, adding no complexity.
317
+ return 1
318
+ elif length == 1 :
319
+ return len (self .domain )
320
+ else :
321
+ # In this case it is effectively cartesian product, i.e.
322
+ # n ** k, where n is the size of the domain and k is the length
323
+ # of the list.
324
+ return len (self .domain ) ** length
305
325
else :
306
- # In this case it is effectively cartesian product, i.e.
307
- # n ** k, where n is the size of the domain and k is the length
308
- # of the list.
309
- return len (self .domain ) ** length
326
+ # Random length which could be one of a number of values.
327
+ assert self .rand_length is not None , "Cannot use possible_lengths " \
328
+ "for a variable with non-random length."
329
+ # For each possible length, the domain is the cartesian
330
+ # product as above, but added together.
331
+ total = 0
332
+ for poss_len in possible_lengths :
333
+ total += len (self .domain ) ** poss_len
334
+ return total
310
335
311
336
def can_use_with_constraint (self ) -> bool :
312
337
'''
@@ -321,30 +346,42 @@ def can_use_with_constraint(self) -> bool:
321
346
# and the domain isn't a dictionary.
322
347
return self .domain is not None and not isinstance (self .domain , dict )
323
348
324
- def get_constraint_domain (self ) -> utils .Domain :
349
+ def get_constraint_domain (self , possible_lengths : Optional [ List [ int ]] = None ) -> utils .Domain :
325
350
'''
326
351
Get a ``constraint`` package friendly version of the domain
327
352
of this random variable.
328
353
354
+ :param possible_lengths: Optional, when there is more than one possiblity
355
+ for the value of the random length, specifies a list of the
356
+ possibilities.
329
357
:return: the variable's domain in a format that will work
330
358
with the ``constraint`` package.
331
359
'''
332
- length = self .get_length ()
333
- if length is None :
334
- # Straightforward, scalar
335
- return self .domain
336
- elif length == 0 :
337
- # List of length zero - an empty list is only correct choice.
338
- return [[]]
339
- elif length == 1 :
340
- # List of length one
341
- return [[x ] for x in self .domain ]
360
+ if possible_lengths is None :
361
+ length = self .get_length ()
362
+ if length is None :
363
+ # Straightforward, scalar
364
+ return self .domain
365
+ elif length == 0 :
366
+ # List of length zero - an empty list is only correct choice.
367
+ return [[]]
368
+ elif length == 1 :
369
+ # List of length one
370
+ return [[x ] for x in self .domain ]
371
+ else :
372
+ # List of greater length, cartesian product.
373
+ # Beware that this may be an extremely large domain.
374
+ # Ensure each element is of type list, which is what
375
+ # we want to return.
376
+ return [list (x ) for x in product (self .domain , repeat = length )]
342
377
else :
343
- # List of greater length, cartesian product.
344
- # Beware that this may be an extremely large domain.
345
- # Ensure each element is of type list, which is what
346
- # we want to return.
347
- return [list (x ) for x in product (self .domain , repeat = length )]
378
+ # For each possible length, return the possible domains.
379
+ # This can get extremely large, even more so than
380
+ # the regular product.
381
+ result = []
382
+ for poss_len in possible_lengths :
383
+ result += [list (x ) for x in product (self .domain , repeat = poss_len )]
384
+ return result
348
385
349
386
def randomize_once (self , constraints : Iterable [utils .Constraint ], check_constraints : bool , debug : bool ) -> Any :
350
387
'''
0 commit comments