Feat: move to global_config, configs for generator
continuous-integration/drone/push Build is failing Details

This commit is contained in:
Bertrand Benjamin 2021-10-03 16:52:54 +02:00
parent b2b204c17b
commit 87b6b3ca27
4 changed files with 86 additions and 67 deletions

View File

@ -7,7 +7,7 @@
# Distributed under terms of the MIT license.
"""
Tools to extract random leafs, random variables, generate random values and
Tools to extract random leaves, random variables, generate random values and
fill new trees
Flow
@ -17,7 +17,7 @@ Tree with RdLeaf
|
| Extract rdLeaf
|
List of leafs to generate
List of leaves to generate
|
| extract_rv
|
@ -27,9 +27,9 @@ List random variables to generate
|
Dictionnary of generated random variables
|
| Compute leafs
| Compute leaves
|
Dictionnary of computed leafs
Dictionnary of computed leaves
|
| Replace
|
@ -46,15 +46,15 @@ Tree with RdLeaf replaced by generated values
/
> {a}
> {a*k}
>>> leafs = rd_t.random_leaf
>>> leafs = ['a', 'a*k']
>>> rd_varia = extract_letters(leafs)
>>> leaves = rd_t.random_leaves
>>> leaves = ['a', 'a*k']
>>> rd_varia = extract_letters(leaves)
>>> sorted(list(rd_varia))
['a', 'k']
>>> generated = random_generator(rd_varia, conditions=['a%2+1'])
>>> generated = random_generator(rd_varia, conditions=['a%2+1'], global_config={"min_max": (-10, 10), "rejected":[0, 1]})
>>> generated # doctest: +SKIP
{'a': 7, 'k': 4}
>>> computed = eval_words(leafs, generated)
>>> computed = eval_words(leaves, generated)
>>> computed # doctest: +SKIP
{'a': 7, 'a*k': 28}
>>> replaced = rd_t.eval_random_leaves(computed)

View File

@ -10,63 +10,60 @@
from random import choice
def build_variable_scope(rd_variables, rejected, min_max, variables_scope):
""" Build variables scope from incomplete one
def complete_variable_configs(variables, global_config:dict={}, configs:dict={})->dict:
""" Completes variables configurations with the global configuration
:param rd_variables: list of random variables to generate
:param rejected: Rejected values for the generator
:param min_max: (min, max) limits in between variables will be generated
:param variables_scope: rejected and min_max define for individual variables
:param variables: list of random variables to generate
:param global_config: global parameters
:param configs: global parameters
:return: complete variable scope
:example:
>>> completed = build_variable_scope(["a", "b", "c", "d"], [0], (-10, 10),
... {"a": {"rejected": [0, 1]},
>>> completed = complete_variable_configs(["a", "b", "c", "d"],
... global_config={"rejected": [], "min_max": (-10, 10)},
... configs={
... "a": {"rejected": [0, 1]},
... "b": {"min_max": (-5, 0)},
... "c": {"rejected": [2], "min_max": (0, 5)}})
>>> complete = {'a': {'rejected': [0, 1], 'min_max': (-10, 10)},
... 'b': {'rejected': [0], 'min_max': (-5, 0)},
... 'c': {'rejected': [2], 'min_max': (0, 5)},
... 'd': {'rejected': [0], 'min_max': (-10, 10)}}
>>> completed == complete
... "c": {"rejected": [2], "min_max": (0, 5)}
... })
>>> completed["a"] == {'rejected': [0, 1], 'min_max': (-10, 10)}
True
>>> completed["b"] == {'rejected': [], 'min_max': (-5, 0)}
True
>>> completed['c'] == {'rejected': [2], 'min_max': (0, 5)}
True
>>> completed['d'] == {'rejected': [], 'min_max': (-10, 10)}
True
"""
complete_scope = variables_scope.copy()
for v in rd_variables:
complete_configs = configs.copy()
for variable in variables:
try:
complete_scope[v]
complete_configs[variable]
except KeyError:
complete_scope[v] = {"rejected": rejected, "min_max": min_max}
complete_configs[variable] = global_config
else:
try:
complete_scope[v]["rejected"]
except KeyError:
complete_scope[v]["rejected"] = rejected
try:
complete_scope[v]["min_max"]
except KeyError:
complete_scope[v]["min_max"] = min_max
return complete_scope
complete_configs[variable] = dict(global_config, **configs[variable])
return complete_configs
def random_generator(
rd_variables, conditions=[], rejected=[0], min_max=(-10, 10), variables_scope={}
):
variables:list[str], conditions:list[str]=[], global_config:dict={}, configs:dict={},
)-> dict[str, int]:
""" Generate random variables
:param rd_variables: list of random variables to generate
:param variables: list of random variables to generate
:param conditions: condition over variables
:param rejected: Rejected values for the generator (default [0])
:param min_max: (min, max) limits in between variables will be generated
:param variables_scope: rejected and min_max define for individual variables
:param global_config: global parameters
:param configs: global parameters
:return: dictionnary of generated variables
:example:
>>> gene = random_generator(["a", "b"],
... ["a > 0"],
... [0], (-10, 10),
... {"rejected": [0], "min_max":(-10, 10)},
... {"a": {"rejected": [0, 1]},
... "b": {"min_max": (-5, 0)}})
... "b": {"min_max": (-5, 0)},
... })
>>> gene["a"] > 0
True
>>> gene["a"] != 0
@ -75,7 +72,8 @@ def random_generator(
True
>>> gene = random_generator(["a", "b"],
... ["a % b == 0"],
... [0, 1], (-10, 10))
... {"rejected": [0, 1], "min_max":(-10, 10)}
... )
>>> gene["a"] not in [0, 1]
True
>>> gene["b"] in list(range(-10, 11))
@ -83,8 +81,8 @@ def random_generator(
>>> gene["a"] % gene["b"]
0
"""
complete_scope = build_variable_scope(
rd_variables, rejected, min_max, variables_scope
complete_scope = complete_variable_configs(
variables, global_config, configs
)
choices_list = {
v: list(
@ -94,17 +92,17 @@ def random_generator(
)
).difference(complete_scope[v]["rejected"])
)
for v in rd_variables
for v in variables
}
# quantity_choices = reduce(lambda x,y : x*y,
# [len(choices_list[v]) for v in choices_list])
# TODO: améliorer la méthode de rejet avec un cache |dim. mai 12 17:04:11 CEST 2019
generate_variable = {v: choice(choices_list[v]) for v in rd_variables}
generate_variable = {v: choice(choices_list[v]) for v in variables}
while not all([eval(c, __builtins__, generate_variable) for c in conditions]):
generate_variable = {v: choice(choices_list[v]) for v in rd_variables}
generate_variable = {v: choice(choices_list[v]) for v in variables}
return generate_variable

View File

@ -1,5 +1,6 @@
from ...core.tree import MutableTree, Tree
from .grammar import extract_letters
from .grammar import extract_letters, eval_words
from .generate import random_generator
from .str2 import rdstr2
class RandomTree(MutableTree):
@ -35,23 +36,18 @@ class RandomTree(MutableTree):
"""
str_2_mut_tree = rdstr2(cls.sink)
return str_2_mut_tree(expression)
def generate(self, conditions:list[str]=[], rejected:list[int]=[0, 1], min_max:tuple[int]=(-10, 10),scopes:dict={}) -> Tree:
""" Generate a random version of self """
pass
@property
def random_leaf(self) -> list[str]:
def random_leaves(self) -> list[str]:
""" Get list of random leaves
:example:
>>> from .leaf import RdLeaf
>>> random_tree = RandomTree("+", RdLeaf("a"), RdLeaf("a*k"))
>>> random_tree.random_leaf
>>> random_tree.random_leaves
['a', 'a*k']
>>> random_tree = RandomTree("+", RdLeaf("a"), 2)
>>> random_tree.random_leaf
>>> random_tree.random_leaves
['a']
"""
rd_leafs = []
@ -78,7 +74,7 @@ class RandomTree(MutableTree):
>>> random_tree.random_value
{'a'}
"""
return extract_letters(self.random_leaf)
return extract_letters(self.random_leaves)
def eval_random_leaves(self, leaves_value:dict[str, int]):
@ -102,3 +98,15 @@ class RandomTree(MutableTree):
except AttributeError:
return leaf
return self.map_on_leaf(replace)
def generate(self, conditions:list[str]=[], config:dict={} , configs:dict={}) -> Tree:
""" Generate a random version of self
:param conditions: list of conditions
:param config: global configuration for generated values
:param configs: specific configuration for each generated values
"""
generated_values = random_generator(self.random_values, config, configs)
leaves = eval_words(self.random_leaves, generated_values)
return self.eval_random_leaves(leaves)

View File

@ -12,7 +12,12 @@ This function ignores tree structure and works with lists
from .core.generate import random_generator
from .core.grammar import extract_letters, eval_words
def list_generator(var_list, conditions=[], rejected=[0], min_max=(-10, 10), variables_scope={}, dictionnary=False):
DEFAUTL_CONFIG = {
"rejected": [0],
"min_max": (-10, 10),
}
def list_generator(var_list:list[str], conditions:list[str]=[], global_config:dict={}, configs:dict={})->list[int]:
""" Generate random computed values from the list
:param rd_variables: list of random variables to generate (can be computed value - "a*b")
@ -20,7 +25,6 @@ def list_generator(var_list, conditions=[], rejected=[0], min_max=(-10, 10), var
:param rejected Rejected values for the generator (default [0])
:param min_max: (min, max) limits in between variables will be generated
:param variables_scope: rejected and min_max define for individual variables
:param dictionnary: the return value will be a dictionnary with var_list as keys (default False)
:return: dictionnary of generated variables
:example:
@ -33,12 +37,21 @@ def list_generator(var_list, conditions=[], rejected=[0], min_max=(-10, 10), var
-20
>>> a, b # doctest: +SKIP
5, -4
>>> list_generator(["a", "a*b", "b", "c"], dictionnary=True) # doctest: +SKIP
{'a': -3, 'a*b': 18, 'b': -6, 'c': -4}
>>> a, ab, b, c = list_generator(["a", "a*b", "b", "c"], conditions=["a-b==0"])
>>> a - b == 0
True
>>> a, ab, b, c = list_generator(["a", "a*b", "b", "c"], global_config={"rejected": [2, 3, 5, 7]})
>>> a not in [2, 3, 5, 7]
True
>>> b not in [2, 3, 5, 7]
True
>>> c not in [2, 3, 5, 7]
True
>>> a, ab, b, c = list_generator(["a", "a*b", "b", "c"], configs={"a": {"rejected": [2, 3, 5, 7]})
>>> a not in [2, 3, 5, 7]
True
"""
rv = extract_letters(var_list)
rv_gen = random_generator(rv, conditions, rejected, min_max, variables_scope)
rv_gen = random_generator(rv, conditions, dict(DEFAUTL_CONFIG, **global_config), variables_scope)
generated = eval_words(var_list, rv_gen)
if dictionnary:
return generated
return [generated[v] for v in var_list]