def sample_space(boundaries, constraints, sample_size, compress_sample=False, compress_region=False, silent=True,
                 debug: bool = False, parallel=10):
    """ Samples the space in **sample_size** samples in each dimension and saves if the point is in respective interval.

    Args:
        constraints  (list of strings): list of constraints
        sample_size (int): number of samples in dimension
        boundaries (list of intervals): subspace to sample, False for default region of space
        compress_sample (bool): if True, only a conjunction of the values (prop in the interval) is used for a sample
        compress_region (bool): if True, only qualitative information (safe, unsafe, neither) about region is returned
        silent (bool): if silent printed output is set to minimum
        debug (bool): if True extensive print will be used
        parallel (bool): flag to run this in parallel mode
    """
    start_time = time()
    global glob_params
    global glob_debug
    global glob_compress
    global glob_constraints

    if compress_region is True:
        compress_sample = True

    if debug:
        silent = False

    if parallel > 1:
        pool_size = parallel
    else:
        pool_size = multiprocessing.cpu_count() - 1

    ## Convert z3 functions
    for index, constraint in enumerate(constraints):
        if is_this_z3_function(constraint):
            constraints[index] = translate_z3_function(constraint)

    parameter_values = []
    if debug:
        print("params", glob_params)
        print("region", boundaries)
        print("sample_size", sample_size)

    ## Create list of parameter values to sample
    for index in range(len(glob_params)):
        parameter_values.append(np.linspace(boundaries[index][0], boundaries[index][1], sample_size, endpoint=True))
    sampling = create_matrix(sample_size, len(glob_params))
    parameter_values = cartesian_product(*parameter_values)

    if not silent:
        print("sampling here")
        print("sample_size", sample_size)
        print("params", glob_params)
        print("parameter_values", parameter_values)
    if debug:
        print("sampling", sampling)

    del sampling
    glob_debug = debug
    glob_compress = compress_sample
    glob_constraints = constraints

    print(colored(f"Sampling initialisation took {round(time() - start_time, 4)} seconds", "yellow")) if not silent else None

    ## ACTUAL SAMPLING
    if parallel:
        ## Parallel sampling
        with multiprocessing.Pool(pool_size) as p:
            sat_list = list(p.map(check_sample, parameter_values))
            ## TODO check how to alter progress when using Pool

    if compress_region:
        if True in sat_list:
            if False in sat_list:
                return "neither"
            else:
                return "safe"
        else:
            return "unsafe"
    else:
        return sat_list
Exemple #2
0
def heatmap(function,
            region,
            sampling_sizes,
            posttitle="",
            where=False,
            parameters=False,
            verbose=False):
    """ Creates 2D heatmap plot of sampled points of given function.

    Args:
        function (string): function to be analysed
        region (list of intervals): boundaries of parameter space to be sampled
        sampling_sizes (list of ints): tuple of sample size of respective parameter
        posttitle (string): A string to be put after the title
        where (tuple/list): output matplotlib sources to output created figure
        parameters (list): list of parameters
        verbose (bool): will input maximum information

    Example:
        heatmap("p+q",[[0,1],[3,4]],[5,5])
    """

    ## Convert z3 function
    if is_this_z3_function(function):
        function = translate_z3_function(function)

    if not parameters:
        parameters = sorted(list(find_param(function)))
    # print(parameters)
    if len(parameters) > 2:
        raise Exception(
            f"Number of parameters of given function is bigger than 2!")

    # f = lambda locals()[parameters[0]),locals()[parameters[1]): fun

    sampling_sizes[0] = sampling_sizes[0] + 1
    if len(parameters) == 1:

        arr = np.zeros((sampling_sizes[0], 3))
        ii = -1
        for i in np.linspace(region[0][0],
                             region[0][1],
                             sampling_sizes[0],
                             endpoint=True):
            ii += 1
            # print("ii: ",ii)
            locals()[parameters[0]] = i
            arr[ii, 0] = round(i, 8)
            arr[ii, 2] = eval(function)

        # print(arr)
        heatmap_data = pd.DataFrame(arr, columns=[parameters[0], "", "E"])
        heatmap_data = heatmap_data.pivot(parameters[0], "", "E")

        vmin = min(arr[:, 2])
        vmax = max(arr[:, 2])
        sqaure = True

    else:
        sampling_sizes[1] = sampling_sizes[1] + 1
        arr = np.zeros((sampling_sizes[0] * sampling_sizes[1], 3))
        ii = -1
        jj = -1
        for i in np.linspace(region[0][0],
                             region[0][1],
                             sampling_sizes[0],
                             endpoint=True):
            ii += 1
            # print("ii: ",ii)
            locals()[parameters[0]] = i
            for j in np.linspace(region[1][0],
                                 region[1][1],
                                 sampling_sizes[1],
                                 endpoint=True):
                jj += 1
                # print("jj: ",jj)
                locals()[parameters[1]] = j
                arr[jj, 0] = round(i, 2)
                arr[jj, 1] = round(j, 2)
                arr[jj, 2] = eval(function)
        # print(arr)
        heatmap_data = pd.DataFrame(
            arr, columns=[parameters[0], parameters[1], "E"])
        heatmap_data = heatmap_data.pivot(parameters[0], parameters[1], "E")

        vmin = min(arr[:, 2])
        vmax = max(arr[:, 2])
        sqaure = False

    if where:
        f, ax = plt.subplots()
        ax = sns.heatmap(heatmap_data,
                         vmin=vmin,
                         vmax=vmax,
                         annot=verbose,
                         square=sqaure)
        title = f"Heatmap \n{posttitle}"
        ax.set_title(wraper.wrap(title))
        ax.invert_yaxis()
        return f
    else:
        ax = sns.heatmap(heatmap_data,
                         vmin=vmin,
                         vmax=vmax,
                         annot=verbose,
                         square=sqaure)
        title = f"Heatmap of the parameter space \n function: {function}"
        ax.set_title(wraper.wrap(title))
        ax.invert_yaxis()
        plt.show()
Exemple #3
0
def sample_list_funs(functions,
                     sample_size,
                     parameters=False,
                     intervals=False,
                     silent: bool = False,
                     debug: bool = False):
    """ Returns a list of function values for sampled parametrisations.

    Args:
        functions: (list of functions) to be sampled
        sample_size (int): sample size in each parameter
        parameters (list of strings): parameter names (used for faster eval)
        intervals (list of pairs of numbers): intervals of parameters
        silent (bool): if silent command line output is set to minimum
        debug (bool): if debug extensive output is provided

    Returns:
        (array): [function index, [parameter values], function value]

    """
    arr = []
    if debug:
        print("Inside of sample_n_visualise.sample_list_funs()")
        print("List_fun: ", functions)
        print("Intervals: ", intervals)

    for index, polynomial in enumerate(functions):
        if is_this_z3_function(polynomial):
            functions[index] = translate_z3_function(polynomial)
        if debug:
            print("Polynomial: ", polynomial)

        if parameters:
            fun_parameters = parameters
        else:
            fun_parameters = set()
            fun_parameters.update(find_param(polynomial, debug))

            ## THIS THING IS WORKING ONLY FOR THE CASE STUDY
            # if len(parameters) < N:
            #     parameters.update(find_param(polynomial, debug))
            if debug:
                print("Parameters: ", fun_parameters)
            fun_parameters = sorted(list(fun_parameters))

        if debug:
            print("Sorted parameters: ", fun_parameters)

        parameter_values = get_param_values(fun_parameters,
                                            sample_size,
                                            intervals=intervals,
                                            debug=debug)

        for parameter_value in parameter_values:
            if debug:
                print("Parameter_value: ", parameter_value)
            a = [functions.index(polynomial)]
            for param_index in range(len(fun_parameters)):
                a.append(parameter_value[param_index])
                if debug:
                    print("Parameter[param]: ", fun_parameters[param_index])
                    print("Parameter_value[param]: ",
                          parameter_value[param_index])
                locals()[fun_parameters[param_index]] = float(
                    parameter_value[param_index])

            # print("polynomial", polynomial)

            value = eval(polynomial)
            if debug:
                print("Eval ", polynomial, value)
            a.append(value)
            arr.append(a)
    return arr
Exemple #4
0
def eval_and_show(functions,
                  parameter_value,
                  parameters=False,
                  data=False,
                  data_intervals=False,
                  cumulative=False,
                  debug: bool = False,
                  where=False):
    """ Creates bar plot of evaluation of given functions for given point in parameter space.

    Args:
        functions (list of strings): list of rational functions
        parameter_value: (list of numbers) array of param values
        parameters (list of strings): parameter names (used for faster eval)
        data (list of floats): Data comparison next to respective function
        data_intervals (list of Intervals): intervals obtained from the data to check if the function are within the intervals
        cumulative (bool): if True cdf instead of pdf is visualised
        debug (bool): if debug extensive output is provided
        where (tuple or list): output matplotlib sources to output created figure
    """
    ## Convert z3 functions
    for index, function in enumerate(functions):
        if is_this_z3_function(function):
            functions[index] = translate_z3_function(function)

    if not parameters:
        parameters = set()
        for function in functions:
            parameters.update(find_param(function, debug))
        parameters = sorted(list(parameters))
    if debug:
        print("Parameters: ", parameters)

    if data:
        ## Check the sizes of data and functions
        if len(data) != len(functions):
            raise Exception(
                f"Number of data points, {len(data)}, is not equal to number of functions, {len(functions)}."
            )
        title = "Rational functions and data \n Parameter values:"
    else:
        title = "Rational functions \n Parameter values:"
    function_values = []
    add = 0
    for param in range(len(parameters)):
        if debug:
            print("Parameters[param]", parameters[param])
            print("Parameter_value[param]", parameter_value[param])
        globals()[parameters[param]] = parameter_value[param]
        title = f"{title} {parameters[param]}={parameter_value[param]},"
    title = title[:-1]

    if data_intervals:
        ## Check the sizes of data and functions
        if len(data_intervals) != len(functions):
            raise Exception(
                f"Number of data intervals, {len(data_intervals)}, is not equal to number of functions, {len(functions)}."
            )
        ## Uniformize the intervals
        data_intervals = to_sympy_intervals(data_intervals)

    title = f"{title}\n Function values: "
    for function in functions:
        expression = eval(function)
        if debug:
            print(function)
            print("Eval ", function, expression)
        if cumulative:
            ## Add sum of all values
            add = add + expression
            function_values.append(add)
            title = f"{title} {add} , "
            del expression
        else:
            function_values.append(expression)
            title = f"{title} {expression} ,"
    title = title[:-2]
    if data:
        # data_to_str = str(data).replace(" ", "\u00A0") does not work
        title = f"{title}\n Data values: {str(data)[1:-1]}"
        if cumulative:
            for index in range(1, len(data)):
                data[index] = data[index] + data[index - 1]
        distance = 0
        for index in range(len(data)):
            try:
                distance = distance + (eval(functions[index]) - data[index])**2
            except IndexError as error:
                raise Exception(
                    f"Unable to show the intervals on the plot. Number of data point ({len(data)}) is not equal to number of functions ({len(functions)})."
                )
        title = f"{title}\n L2 Distance: {distance}"

    if where:
        fig = where[0]
        ax = where[1]
        plt.autoscale()
        ax.autoscale()
    else:
        fig, ax = plt.subplots()
    width = 0.2
    ax.set_ylabel(f'{("Value", "Cumulative value")[cumulative]}')
    if data:
        ax.set_xlabel(
            'Rational function indices (blue bars), Data point indices (red bars)'
        )
        # if data_intervals:
        #     functions_inside_of_intervals = []
        #     for index in range(len(data)):
        #         try:
        #             if function_values[index] in data_intervals[index]:
        #                 functions_inside_of_intervals.append(True)
        #             else:
        #                 functions_inside_of_intervals.append(False)
        #         except IndexError as error:
        #             raise Exception(f"Unable to show the intervals on the plot. Number of data intervals ({len(data_intervals)}) is not equal to number of functions ({len(functions)}).")
        #
        #     # functions_inside_of_intervals_to_str = str(functions_inside_of_intervals).replace(" ", "\u00A0") - does not work
        #     title = f"{title} \n Function value within the respective interval: {functions_inside_of_intervals}"
    else:
        ax.set_xlabel('Rational function indices')
    ax.xaxis.set_major_locator(FixedLocator(range(1,
                                                  len(function_values) + 1)))
    ax.bar(range(1,
                 len(function_values) + 1),
           function_values,
           width,
           color='b',
           label="function")
    if data:
        if data_intervals:
            # np.array(list(map(lambda x: np.array([x.start, x.end]), data_intervals))) # wrong shape (N,2) instead of (2,N)
            errors = [[], []]
            for index, item in enumerate(data_intervals):
                errors[0].append(float(abs(data[index] - item.start)))
                errors[1].append(float(abs(data[index] - item.end)))

            ax.bar(list(map(lambda x: x + width, range(1,
                                                       len(data) + 1))),
                   data,
                   width,
                   yerr=errors,
                   color='r',
                   capsize=10,
                   label="data")
            title = f"{title}\n Data intervals visualised as error bars."
        else:
            ax.bar(list(map(lambda x: x + width, range(1,
                                                       len(data) + 1))),
                   data,
                   width,
                   color='r',
                   label="data")
    ax.set_title(wraper.wrap(title))
    # fig.legend()
    if debug:
        print("Len(fun_list): ", len(functions))
        print("values:", function_values)
        print("range:", range(1, len(function_values) + 1))
        print("title", title)
    if where:
        return fig, ax
    else:
        plt.show()
    return function_values
Exemple #5
0
def sample_region(region, params, constraints, sample_size, boundaries=False, compress=False, silent=True, save=False,
                  debug=False, progress=False, quantitative=False, parallel=True, save_memory=False, stop_on_unknown=False):
    """ Samples the space in **sample_size** samples in each dimension and saves if the point is in respective interval.

    Args:
        region: (Rectangle): region to be sampled
        params: (list of strings): parameters
        constraints  (list of strings): list of constraints
        sample_size (int): number of samples in dimension
        boundaries (list of intervals): subspace to sample, False for default region of space
        compress (bool): if True, only a conjunction of the values (prop in the interval) is used
        silent (bool): if silent printed output is set to minimum
        debug (bool): if True extensive print will be used
        save (bool): if True output is pickled
        debug (bool): if True extensive print will be used
        progress (Tkinter element): progress bar
        quantitative (bool): if True return how far is the point from satisfying / not satisfying the constraints
        parallel (bool): flag to run this in parallel mode
        save_memory (bool): if True saves only sat samples
    """
    start_time = time()
    global glob_space
    global glob_debug
    global glob_compress
    global glob_constraints

    ## TODO this can be optimised using check_sample without using space
    glob_space = RefinedSpace(region, params)

    assert isinstance(region, Iterable)
    if debug:
        silent = False

    if parallel is True:
        pool_size = multiprocessing.cpu_count() - 1
    elif parallel > 1:
        pool_size = min(parallel, multiprocessing.cpu_count() - 1)
    elif parallel == 1:
        pool_size = 1

    ## Convert z3 functions
    for index, constraint in enumerate(constraints):
        if is_this_z3_function(constraint):
            constraints[index] = translate_z3_function(constraint)

    ## Convert constraints for quantitative sampling
    if quantitative:
        constraints = copy(constraints)
        constraints = list(map(normalise_constraint, constraints))

        ## Split constraints into two pairs ((left, mid)(mid, right)) or ((left, right), None)
        constraints = split_constraints(constraints)

    parameter_values = []
    if debug:
        print("space.params", params)
        print("space.region", region)
        print("sample_size", sample_size)

    ## Create list of parameter values to sample
    for index in range(len(params)):
        if boundaries:
            parameter_values.append(np.linspace(boundaries[index][0], boundaries[index][1], sample_size, endpoint=True))
        else:
            parameter_values.append(np.linspace(region[index][0], region[index][1], sample_size, endpoint=True))
    sampling = create_matrix(sample_size, len(params))
    parameter_values = cartesian_product(*parameter_values)

    if not silent:
        print("sampling here")
        print("sample_size", sample_size)
        print("params", params)
        print("parameter_values", parameter_values)
    if debug:
        print("sampling", sampling)

    del sampling
    glob_debug = debug
    glob_compress = compress
    glob_constraints = constraints

    print(colored(f"Sampling initialisation took {round(time() - start_time, 4)} seconds", "yellow")) if not silent else None

    ## ACTUAL SAMPLING
    if parallel and not quantitative:
        ## Parallel sampling
        if stop_on_unknown:
            ## TODO implement this, very good idea on paper
            raise NotImplementedError("this optimisation is not implemented so far, please use option stop_on_unknown=False")
            current = None
            with multiprocessing.Pool(pool_size) as p:
                check_samplee = partial(check_sample, silent=silent)
                results = [p.apply_async(check_samplee, item).get() for item in parameter_values]

            print(results)
            return results
            #     for item in parameter_values:
            #         print("item", item)
            #         result = p.apply_async(check_sample, item)
            #         print("result, ", result)
            #         if current is None:
            #             if result is True:
            #                 current = "safe"
            #             else:
            #                 current = "unsafe"
            #         elif current == "safe":
            #             if result is False:
            #                 current = "neither"
            #                 p.terminate()
            #         elif current == "unsafe":
            #             if result is True:
            #                 current = "neither"
            #                 p.terminate()
            # return current
        else:
            with multiprocessing.Pool(pool_size) as p:
                sat_list = list(p.map(check_sample, parameter_values))

    elif parallel and quantitative:
        ## Parallel quantitative sampling
        with multiprocessing.Pool(pool_size) as p:
            dist_list = list(p.map(sample_sat_degree, parameter_values))

    elif not quantitative:
        ## Sequential sampling
        sat_list, unsat_list = [], []
        for index, item in enumerate(parameter_values):
            spam = check_sample(item, save_memory, silent=silent)
            if spam is True:
                sat_list.append(item)
            elif spam is False:
                unsat_list.append(item)
            else:
                pass
                # warnings.filterwarnings("ignore")
                # raise Warning(f"Checking {parameter_values} resulted in unexpected value: {spam}")
            if progress:
                progress(index / len(parameter_values))
    else:
        ## Sequential quantitative sampling
        dist_map = {}
        for index, item in enumerate(parameter_values):
            dist_map[item] = sample_sat_degree(item)

            if progress:
                progress(index / len(parameter_values))

    ## Setting flag to not visualise sat if no unsat and vice versa
    print(colored(f"Sampling took {round(time()-start_time, 4)} seconds", "yellow")) if not silent else None

    if parallel:
        if quantitative:
            return dist_list
        else:
            return sat_list
    else:
        if quantitative:
            return dist_map
        else:
            return sat_list, unsat_list
Exemple #6
0
def optimize(functions: [list],
             params: [list],
             param_intervals: [list],
             data_point: [list],
             weights=False,
             debug=False):
    """ Search for parameter values minimizing the distance of function to data.

    Args:
        functions (list): of functions to be optimized
        params (list): of functions parameters
        param_intervals (list): of intervals of functions parameters
        data_point (list): of values of functions to be optimized
        weights (list): of weights to multiply the respective distance with
        debug (bool): if True extensive print will be used

    Returns:
        (list): [point of parameter space with the least distance, values of functions in the point, the distance between the data and functions values]
    """

    assert len(functions) == len(data_point)
    assert len(params) == len(param_intervals)
    if weights:
        assert len(weights) == len(data_point)

    ## Convert z3 functions
    for index, function in enumerate(functions):
        if is_this_z3_function(function):
            functions[index] = translate_z3_function(function)

    ## Get the average value of parameter intervals
    x0 = np.array(list(map(lambda lst: (lst[0] + lst[1]) / 2,
                           param_intervals)))

    globals()["functions"] = functions
    # print("globals()[functions]", globals()["functions"])
    globals()["params"] = params
    # print("globals()[params]", globals()["params"])
    globals()["data_point"] = data_point
    # print("globals()[data_point]", globals()["data_point"])

    bounds = [[], []]
    for interval in param_intervals:
        bounds[0].append(interval[0])
        bounds[1].append(interval[1])
    # print("bounds", bounds)

    if debug:
        verbose = 2
    else:
        verbose = 0

    if weights:
        res = scipy.optimize.least_squares(weighted_dist,
                                           x0,
                                           bounds=bounds,
                                           args=[weights],
                                           verbose=verbose)
    else:
        res = scipy.optimize.least_squares(dist,
                                           x0,
                                           bounds=bounds,
                                           verbose=verbose)
    # print(res.x)

    ## VALUES OF PARAMS, VALUES OF FUNCTIONS, DISTANCE
    # print("point", list(res.x))
    ## function_values = res.fun
    ## for index, item in enumerate(function_values):
    ##     function_values[index] = function_values[index] + data_point[index]
    if debug:
        print(res)
        print("params", params)
        ## !!! THIS IS NOT UPDATED RESULT
        # spam = []
        # for item in params:
        #     spam.append(globals()[item])
        # print("param values", spam)
        print("param values", list(res.x))
        print("function values", list(map(eval, functions)))
        print("distance values", list(res.fun))
        print("total distance according to scipy - not transformed", res.cost)
        ## !!! THIS IS NOT UPDATED RESULT
        # print("L1 distance", sum([abs(x - y) for x, y in zip(list(map(eval, functions)), data_point)]))
        # print("L2 distance", (sum([(x - y)**2 for x, y in zip(list(map(eval, functions)), data_point)]))**(1/2))

        for index, value in enumerate(params):
            globals()[str(value)] = res.x[index]
        print(
            "L1 distance",
            sum([
                abs(x - y)
                for x, y in zip(list(map(eval, functions)), data_point)
            ]))
        print("L2 distance", (sum([
            (x - y)**2 for x, y in zip(list(map(eval, functions)), data_point)
        ]))**(1 / 2))
    return list(res.x), list(map(eval, functions)), (2 * res.cost)**(1 / 2)