diff --git a/mapytex/calculus/core/random/__init__.py b/mapytex/calculus/core/random/__init__.py index 2b6ced4..e7af569 100644 --- a/mapytex/calculus/core/random/__init__.py +++ b/mapytex/calculus/core/random/__init__.py @@ -49,6 +49,7 @@ Tree with RdLeaf replaced by generated values """ +from random import choice from .leaf import RdLeaf def extract_rdleaf(tree): @@ -124,3 +125,95 @@ def replace_rdleaf(tree, computed_leafs): return leaf return tree.map_on_leaf(replace) + +def random_generator(rd_variables, + conditions = [], + rejected = [0], + min_max = (-10, 10), + variables_scope = {}): + """ Generate random variables + + :param rd_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 + :return: dictionnary of generated variables + + :example: + >>> gene = random_generator(["a", "b"], + ... ["a > 0"], + ... [0], (-10, 10), + ... {"a": {"rejected": [0, 1]}, + ... "b": {"min_max": (-5, 0)}}) + >>> gene["a"] > 0 + True + >>> gene["a"] != 0 + True + >>> gene["b"] < 0 + True + >>> gene = random_generator(["a", "b"], + ... ["a % b == 0"], + ... [0, 1], (-10, 10)) + >>> gene["a"] not in [0, 1] + True + >>> gene["b"] in list(range(-10, 11)) + True + >>> gene["a"] % gene["b"] + 0 + """ + complete_scope = build_variable_scope(rd_variables, + rejected, min_max, + variables_scope) + choices_list = {v: list(set(range( + complete_scope[v]["min_max"][0], complete_scope[v]["min_max"][1]+1) + ).difference(complete_scope[v]["rejected"])) + for v in rd_variables} + + generate_variable = {v: choice(choices_list[v]) for v in rd_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} + + return generate_variable + +def build_variable_scope(rd_variables, rejected, min_max, variables_scope): + """ Build variables scope from incomplete one + + :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 + :return: complete variable scope + + :example: + >>> completed = build_variable_scope(["a", "b", "c", "d"], [0], (-10, 10), + ... {"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 + True + """ + complete_scope = variables_scope + for v in rd_variables: + try: + complete_scope[v] + except KeyError: + complete_scope[v] = {"rejected": rejected, "min_max": min_max} + 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 + + +