@@ -253,6 +253,14 @@ def get_length(self) -> int:
253253 " but none was given when get_length was called." )
254254 return self .rand_length_val
255255
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+
256264 def set_rand_length (self , length : int ) -> None :
257265 '''
258266 Function to set the random length.
@@ -282,31 +290,48 @@ def _get_random(self) -> random.Random:
282290 return random
283291 return self ._random
284292
285- def get_domain_size (self ) -> int :
293+ def get_domain_size (self , possible_lengths : Optional [ List [ int ]] = None ) -> int :
286294 '''
287295 Return total domain size, accounting for length of this random variable.
288296
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.
289300 :return: domain size, integer.
290301 '''
291302 if self .domain is None :
292303 # If there's no domain, it means we can't estimate the complexity
293304 # of this variable. Return 1.
294305 return 1
295306 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
305325 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
310335
311336 def can_use_with_constraint (self ) -> bool :
312337 '''
@@ -321,30 +346,42 @@ def can_use_with_constraint(self) -> bool:
321346 # and the domain isn't a dictionary.
322347 return self .domain is not None and not isinstance (self .domain , dict )
323348
324- def get_constraint_domain (self ) -> utils .Domain :
349+ def get_constraint_domain (self , possible_lengths : Optional [ List [ int ]] = None ) -> utils .Domain :
325350 '''
326351 Get a ``constraint`` package friendly version of the domain
327352 of this random variable.
328353
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.
329357 :return: the variable's domain in a format that will work
330358 with the ``constraint`` package.
331359 '''
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 )]
342377 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
348385
349386 def randomize_once (self , constraints : Iterable [utils .Constraint ], check_constraints : bool , debug : bool ) -> Any :
350387 '''
0 commit comments