From 8cc2316ce7ca10f34b43846cd428b1c7fddd8aaf Mon Sep 17 00:00:00 2001 From: Krzysztof Rudnicki Date: Mon, 17 Apr 2023 22:49:40 +0200 Subject: [PATCH] feat: make code conform to pylint --- .vscode/settings.json | 3 + lab3/main.py | 264 ++++++++++++++++++++++++------------------ 2 files changed, 156 insertions(+), 111 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..98ec6877 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.linting.pylintArgs": ["--generate-members"] +} \ No newline at end of file diff --git a/lab3/main.py b/lab3/main.py index 514d4230..ac2cf742 100644 --- a/lab3/main.py +++ b/lab3/main.py @@ -13,119 +13,154 @@ import numpy as np def rastrigin(x_argument, y_argument): - """ Define the Rastrigin function """ - return 20 + x_argument**2 - 10 * np.cos(2 * np.pi * x_argument) + \ - y_argument**2 - 10 * np.cos(2 * np.pi * y_argument) + """Define the Rastrigin function""" + return ( + 20 + + x_argument**2 + - 10 * np.cos(2 * np.pi * x_argument) + + y_argument**2 + - 10 * np.cos(2 * np.pi * y_argument) + ) -def generate(population, - number_of_parents=5, - size_of_population=20, - mutation_strength=0.1, - ): - """ Run single generation """ +def generate( + population, + arguments +): + """Run single generation""" # Evaluate the fitness of each individual - fitness = np.array([rastrigin(x_point_value, y_point_value) - for x_point_value, y_point_value in population]) + fitness = np.array( + [ + rastrigin(x_point_value, y_point_value) + for x_point_value, y_point_value in population + ] + ) - # Select the top number_of_parents individuals - parents = population[np.argsort(fitness)[:number_of_parents]] + # Select the top arguments["number_of_parents"] individuals + parents = population[np.argsort(fitness)[:arguments["number_of_parents"]]] # Generate the next generation of lambda individuals by recombination children = np.concatenate( - [np.random.permutation(parents) for i in range((size_of_population//number_of_parents)+1)]) - children = children[:size_of_population] + [ + np.random.permutation(parents) + for i in range((arguments["size_of_population"] // arguments["number_of_parents"]) + 1) + ] + ) + children = children[:arguments["size_of_population"]] # Add mutation to the children mutation = np.random.normal( - loc=0, scale=mutation_strength, size=( - size_of_population, 2)) + loc=0, scale=arguments["mutation_strength"], size=(arguments["size_of_population"], 2) + ) population = children + mutation return fitness, population + def evolution_strategy( - number_of_parents=5, - size_of_population=20, - mutation_strength=0.1, - number_of_generations=123, - min_max=(-5.12, 5.12), - number_of_outputs = 10, - no_display = False, - save_results = False + arguments, + no_display=False, ): - """ Define the Evolutionary Strategy (μ, λ) algorithm """ + """Define the Evolutionary Strategy (μ, λ) algorithm""" # Initialize the population print_info = [] population = np.random.uniform( - low=min_max[0], high=min_max[1], size=( - size_of_population, 2)) + low=arguments["min"], high=arguments["max"], size=(arguments["size_of_population"], 2) + ) summary = [] if not no_display: - print_info.append((population, 0, f"0:nop-{number_of_parents}:sop-{size_of_population}:ms-{mutation_strength}:nog-{number_of_generations}:min-max-{min_max}:noo-{number_of_outputs}")) - number_of_outputs = min([number_of_outputs-1, number_of_generations]) + print_info.append( + (population, + 0, + f"""0:nop-{arguments["number_of_parents"]}:sop-{arguments["size_of_population"]}: + ms-{arguments["mutation_strength"]}:nog-{arguments["number_of_generations"]}: + min-max-{arguments["min"], arguments["max"]}:noo-{arguments["number_of_outputs"]}""", + )) + arguments["number_of_outputs"] = min( + [arguments["number_of_outputs"] - 1, arguments["number_of_generations"]]) # Iterate until we reach max number of generate and terminate - for generation_number in range(1, number_of_generations+1): + for generation_number in range(1, arguments["number_of_generations"] + 1): fitness, population = generate( - population, - number_of_parents, - size_of_population, - mutation_strength) - step = number_of_generations//number_of_outputs \ - if number_of_generations % number_of_outputs == 0 \ - else number_of_generations//(number_of_outputs-1) - offset = number_of_generations % step + population, arguments) + step = ( + arguments["number_of_generations"] // arguments["number_of_outputs"] + if arguments["number_of_generations"] % arguments["number_of_outputs"] == 0 + else arguments["number_of_generations"] // (arguments["number_of_outputs"] - 1) + ) + offset = arguments["number_of_generations"] % step if (generation_number - offset) % step == 0 and not no_display: - print_info.append((population, generation_number, f"{generation_number}:nop_{number_of_parents}:sop_{size_of_population}:ms_{mutation_strength}:nog_{number_of_generations}:min_max_{min_max}:noo_{number_of_outputs}")) + print_info.append( + (population, + generation_number, + f"""{generation_number}:nop_{arguments["number_of_parents"]}: + sop_{arguments["size_of_population"]}:ms_{arguments["mutation_strength"]}: + nog_{arguments["number_of_generations"]}: + min_max_{arguments["min"], arguments["max"]}: + noo_{arguments["number_of_outputs"]}""", + )) summary.append(population) # Evaluate the fitness of the final population - fitness = np.array([rastrigin(x_point_value, y_point_value) - for x_point_value, y_point_value in population]) + fitness = np.array( + [ + rastrigin(x_point_value, y_point_value) + for x_point_value, y_point_value in population + ] + ) # Return the best individual found best_idx = np.argmin(fitness) - return population[best_idx], fitness[best_idx], population, total_time, print_info, summary + return ( + population[best_idx], + fitness[best_idx], + population, + print_info, + summary, + ) def print_help(): - """ Print program functionality and how to access it """ - print(""" - python main.py - Default functionality optimizing Rastrigin function file_ (x_point_value, y_point_value) = + """Print program functionality and how to access it""" + print( + """ + python main.py - Default functionality optimizing + Rastrigin function file_ (x_point_value, y_point_value) = 20 + (x_point_value^2 - 10cos(2πx)) + (y_point_value^2 - 10 cos(2πy)) using Evolutionary Strategy (μ, λ), using only default values Default values: - number_of_parents=5, - size_of_population=20, - mutation_strength=0.1, - number_of_generations=100, + arguments["number_of_parents"]=5, + arguments["size_of_population"]=20, + arguments["mutation_strength"]=0.1, + arguments["number_of_generations"]=100, min_value=-5.12, max_value=5.12 - number_of_outputs = 100 + arguments["number_of_outputs"] = 100 python main.py -h --help print this prompt Any of the default values an be changed using arguments: - -nop --number_of_parents [number] - -sop --size_of_population [number] - -ms --mutation_strength [number] - -nog --number_of_generations [number] + -nop --arguments["number_of_parents"] [number] + -sop --arguments["size_of_population"] [number] + -ms --arguments["mutation_strength"] [number] + -nog --arguments["number_of_generations"] [number] -min --min_value [number] -max --max_value [number] - -noo, --number_of_outputs [number] - Those arguments can be given in any order and any argument which was not entered will be replaced with default value, + -noo, --arguments["number_of_outputs"] [number] + Those arguments can be given in any order and any argument + which was not entered will be replaced with default value, Additional flags: -nd, --no-display (does not show the plots) -s, --save (if issued WILL save the files) exemplary use: python main.py -nop 5 -sop 20 -ms 0.1 -i 100 -min -5.12 -max 5.12 -noo 100 - """) + """ + ) def get_output_bounds(x_data, y_data): """Get x and y output limits for pyplot""" # min_size = 0.2 - min_output_size = ARGUMENTS["mutation_strength"]*10 + min_output_size = ARGUMENTS["mutation_strength"] * 10 xmin = min(x_data) xmax = max(x_data) @@ -137,21 +172,25 @@ def get_output_bounds(x_data, y_data): if min_output_size is None: min_output_size = max(x_diff, y_diff) - margin = max(x_diff, y_diff)/5 + margin = max(x_diff, y_diff) / 5 if x_diff < min_output_size: - xmax += (min_output_size - x_diff)/2 - xmin -= (min_output_size - x_diff)/2 + xmax += (min_output_size - x_diff) / 2 + xmin -= (min_output_size - x_diff) / 2 if y_diff < min_output_size: - ymax += (min_output_size - y_diff)/2 - ymin -= (min_output_size - y_diff)/2 - x_bounds = [xmin-margin, xmax+margin] - y_bounds = [ymin-margin, ymax+margin] + ymax += (min_output_size - y_diff) / 2 + ymin -= (min_output_size - y_diff) / 2 + x_bounds = [xmin - margin, xmax + margin] + y_bounds = [ymin - margin, ymax + margin] return x_bounds, y_bounds -def output(population_output, generation_number, file_name = "temp", save_results = False): - """ Draw result of our function """ +def output( + population_output, + generation_number, + file_name="temp", + save_results=False): + """Draw result of our function""" # define the visualization params colors = np.random.rand(len(population_output)) @@ -193,12 +232,8 @@ def output(population_output, generation_number, file_name = "temp", save_result os.unlink(file_.name) -def print_summary(populations, file_name = "temp_summary", save_results = False): - """ Draw result of our function for chosen generations """ - - # define the visualization params - main_color = [[1, 1, 1]] * len(populations[0]) - final_color = [[0, 1, 0]] * len(populations[0]) +def print_summary(populations, file_name="temp_summary", save_results=False): + """Draw result of our function for chosen generations""" with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as file_: # iterate over the optimization steps @@ -217,10 +252,14 @@ def print_summary(populations, file_name = "temp_summary", save_results = False) if ind == 0: bounds = get_output_bounds(x_data, y_data) # plot the data - transparency = ind/(len(populations)-1) + transparency = ind / (len(populations) - 1) color = [[transparency, 0, 0]] * len(pop) - plt.scatter(x_data, y_data, c=color, - alpha=transparency, label=f"{ind}") + plt.scatter( + x_data, + y_data, + c=color, + alpha=transparency, + label=f"{ind}") plt.xlim(bounds[0]) plt.ylim(bounds[1]) plt.savefig(file_.name) @@ -231,8 +270,7 @@ def print_summary(populations, file_name = "temp_summary", save_results = False) cv2.imwrite("SUMMARY:" + file_name + ".jpg", image) # show the image, provide window name first - cv2.imshow(f"Summary", image) - + cv2.imshow("Summary", image) # add wait key. window waits until user presses a key and quits if # the key is 'q' @@ -247,7 +285,7 @@ def print_summary(populations, file_name = "temp_summary", save_results = False) def user_input(): - """ Handle user terminal arguments""" + """Handle user terminal arguments""" arguments = { "number_of_parents": 5, "size_of_population": 20, @@ -257,61 +295,65 @@ def user_input(): "max": 5.12, "number_of_outputs": 10, "no_display": False, - "save": False} + "save": False, + } for index, argument in enumerate(sys.argv): - if argument in ('-h', '--help'): + if argument in ("-h", "--help"): print_help() sys.exit() - if argument in ('-nop', '--number_of_parents'): - arguments["number_of_parents"] = int(sys.argv[index+1]) - if argument in ('-sop', '--size_of_population'): - arguments["size_of_population"] = int(sys.argv[index+1]) - if argument in ('-ms', '--mutation_strength'): - arguments["mutation_strength"] = float(sys.argv[index+1]) - if argument in ('-nog', '--number_of_generations'): - arguments["number_of_generations"] = int(sys.argv[index+1]) - if argument in ('-min', '--min_value'): - arguments["min"] = float(sys.argv[index+1]) - if argument in ('-max', '--max_value'): - arguments["max"] = float(sys.argv[index+1]) - if argument in ('-noo', '--number_of_outputs'): + if argument in ("-nop", "--number_of_parents"): + arguments["number_of_parents"] = int(sys.argv[index + 1]) + if argument in ("-sop", "--size_of_population"): + arguments["size_of_population"] = int(sys.argv[index + 1]) + if argument in ("-ms", "--mutation_strength"): + arguments["mutation_strength"] = float(sys.argv[index + 1]) + if argument in ("-nog", "--number_of_generations"): + arguments["number_of_generations"] = int(sys.argv[index + 1]) + if argument in ("-min", "--min_value"): + arguments["min"] = float(sys.argv[index + 1]) + if argument in ("-max", "--max_value"): + arguments["max"] = float(sys.argv[index + 1]) + if argument in ("-noo", "--number_of_outputs"): arguments["number_of_outputs"] = int(sys.argv[index + 1]) - if argument in ('-nd', '--no_display'): + if argument in ("-nd", "--no_display"): arguments["no_display"] = True - if argument in ('-s', '--save'): + if argument in ("-s", "--save"): arguments["save"] = True return arguments + def print_output(print_info, save_results, summary): + """ Prints out population and summary plots """ for population, generation_number, file_name in print_info: output(population, generation_number, file_name, save_results) summary_file_name = file_name print_summary(summary, summary_file_name, save_results) + # Ran first in the code if __name__ == "__main__": # Run the Evolutionary Strategy algorithm ARGUMENTS = user_input() - total_time = 0 + TOTAL_TIME = 0 start_time = time.perf_counter() - best_individual, best_fitness, output_population, generation_time, print_info, summary = evolution_strategy( - ARGUMENTS["number_of_parents"], - ARGUMENTS["size_of_population"], - ARGUMENTS["mutation_strength"], - ARGUMENTS["number_of_generations"], - (ARGUMENTS["min"], ARGUMENTS["max"]), - ARGUMENTS["number_of_outputs"], + ( + best_individual, + best_fitness, + output_population, + PRINT_INFO, + SUMMARY, + ) = evolution_strategy( + ARGUMENTS, ARGUMENTS["no_display"], - ARGUMENTS["save"]) + ) end_time = time.perf_counter() if not ARGUMENTS["no_display"]: - print_output(print_info, ARGUMENTS["save"], summary) - total_time = end_time - start_time - time_per_generation = total_time / \ - ARGUMENTS["number_of_generations"] + print_output(PRINT_INFO, ARGUMENTS["save"], SUMMARY) + TOTAL_TIME = end_time - start_time + time_per_generation = TOTAL_TIME / ARGUMENTS["number_of_generations"] print("Best individual found:", best_individual) print("Best fitness found:", best_fitness) - print("total_generation_time: ", total_time) + print("total_generation_time: ", TOTAL_TIME) print("time_per_generation: ", time_per_generation)