def main(): t_t_0 = time.monotonic() err = "{} -c <simulation.sumocfg (path)> -s <searchspace.json (path)> -p <Population size (int)> -g <Number of generations (int)> [-r <Seed (hex string)> -k <crossover points (int)> -x <mutation rate 0..1 (float)> -o <best net (Path)> -t <timeout sec (int)> -v verbose (specify multiple times for more messages) [-l local multiprocessing | -m mpi]]" individual_id_ctr = 1 simulation_cfg_path = False searchspace_path = False population_size = False number_of_generations = False seed = False best_net_path = False v = 0 use_local_mt = False use_mpi = False k_num = False mutation_rate = False timeout_s = None try: opts, args = getopt.getopt(sys.argv[1:], "vlmc:s:p:g:r:k:x:o:t:") except getopt.GetoptError: print(err.format(sys.argv[0])) sys.exit(1) for o, a in opts: if o == "-s": searchspace_path = a elif o == "-c": simulation_cfg_path = a elif o == "-p": population_size = a elif o == "-g": number_of_generations = a elif o == "-r": seed = a elif o == "-v": v += 1 elif o == "-l": use_local_mt = True elif o == "-m": use_mpi = True elif o == "-k": k_num = a elif o == "-x": mutation_rate = a elif o == "-o": best_net_path = a elif o == "-t": timeout_s = a if simulation_cfg_path is False or searchspace_path is False or population_size is False or number_of_generations is False: print(err.format(sys.argv[0]), file=sys.stderr) sys.exit(1) if use_local_mt and use_mpi: print("Only local multiprocessing xor mpi!") print(err.format(sys.argv[0]), file=sys.stderr) sys.exit(1) if use_local_mt: op_mode = GenEvoConstants.MODE_LMT elif use_mpi: op_mode = GenEvoConstants.MODE_MPI else: op_mode = GenEvoConstants.MODE_LOC searchspace_path = Path(searchspace_path).resolve() if not searchspace_path.exists() or searchspace_path.is_dir(): print("No valid searchspace file found!", file=sys.stderr) print(err.format(sys.argv[0]), file=sys.stderr) sys.exit(1) simulation_cfg_path = Path(simulation_cfg_path).resolve() if not simulation_cfg_path.exists() or searchspace_path.is_dir(): print("No valid sumo config file found!", file=sys.stderr) print(err.format(sys.argv[0]), file=sys.stderr) sys.exit(1) if not best_net_path is False: best_net_path = Path(best_net_path).resolve() if best_net_path.is_dir() or not best_net_path.parent.is_dir(): print("No valid location for best net specified!", file=sys.stderr) print(err.format(sys.argv[0]), file=sys.stderr) sys.exit(1) conf_tree = ET.parse(simulation_cfg_path) conf_root = conf_tree.getroot() net_path = Path( simulation_cfg_path.parent, conf_root.find("input").find("net-file").attrib["value"]).resolve() trips_path = Path( simulation_cfg_path.parent, conf_root.find("input").find("route-files").attrib["value"]).resolve() vtypes_path = Path( simulation_cfg_path.parent, conf_root.find("input").find( "additional-files").attrib["value"]).resolve() del conf_root del conf_tree if v >= GenEvoConstants.V_INF: print("Using net file: <{}>.".format(str(net_path))) print("Using trips file: <{}>.".format(str(trips_path))) try: population_size = int(population_size) number_of_generations = int(number_of_generations) if population_size < 3 or population_size % 4 != 0: print( "Please specify only numbers greater than 2 and dividable by 4 for population size!", file=sys.stderr) raise ValueError() if number_of_generations < 2: print("Please specify a number of generations greater than 1!", file=sys.stderr) raise ValueError() except ValueError: print( "Population size and number of generations and number of crossover points must be integers!", file=sys.stderr) print(err.format(sys.argv[0]), file=sys.stderr) sys.exit(1) if v >= GenEvoConstants.V_INF: print("Population size is {}; Number of generations is {}".format( population_size, number_of_generations)) if k_num is False: k_num = 20 else: try: k_num = int(k_num) if k_num < 1: raise ValueError() except ValueError: print("Number of crossover points must be nonnegativ integer", file=sys.stderr) print(err.format(sys.argv[0]), file=sys.stderr) sys.exit(1) if mutation_rate is False: mutation_rate = 0.05 else: try: mutation_rate = float(mutation_rate) if mutation_rate < 0. or mutation_rate > 1.: raise ValueError except ValueError: print( "Mutation rate must be a floating point value between 0 and 1!", file=sys.stderr) print(err.format(sys.argv[0]), file=sys.stderr) sys.exit(1) if v >= GenEvoConstants.V_INF: print("Using {}-point crossover and mutation rate of {}.".format( k_num, mutation_rate)) if seed is False: seed = int(binascii.hexlify(os.urandom(16)), 16) else: try: seed = int(seed, 16) except ValueError: print("Seed has to be a hexadecimal string!", file=sys.stderr) print(err.format(sys.argv[0]), file=sys.stderr) sys.exit(1) stable_random = random.Random() stable_random.seed(seed) if v >= GenEvoConstants.V_INF: print("Using seed: {0:x}".format(seed)) if not timeout_s is None: try: timeout_s = int(timeout_s) if timeout_s < 1: raise ValueError() except ValueError: print( "Please specify timeout as integer and at least 1 second long!", file=sys.stderr) print(err.format(sys.argv[0]), file=sys.stderr) sys.exit(1) if v >= GenEvoConstants.V_INF: print("Setting timeout for subprocesses to {}s.".format(timeout_s)) with open(searchspace_path, "r") as f: searchspace = json.loads(f.read()) if v >= GenEvoConstants.V_INF: print("Searchspace: {} intersections and {} roundabouts found.".format( len(searchspace["intersections"]), len(searchspace["roundabouts"]))) ##Prepare workers if v >= GenEvoConstants.V_DBG: print("Start preparing workers...", end="", flush=True) with open(simulation_cfg_path, "r") as f: simulation_cfg_str = f.read() with open(trips_path, "r") as f: trips_str = f.read() with open(vtypes_path, "r") as f: vtypes_str = f.read() netcnvt = load_netconvert_binary() tmpd, plain_files = cnvt_net_to_plain(net_path, netcnvt, "prepare", False) with open(plain_files["con"], "r") as f: plain_con_str = f.read() with open(plain_files["edg"], "r") as f: plain_edg_str = f.read() with open(plain_files["nod"], "r") as f: plain_nod_str = f.read() plain_tll_str = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<tlLogics version=\"1.1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://sumo.dlr.de/xsd/tllogic_file.xsd\">\n</tlLogics>" with open(plain_files["typ"], "r") as f: plain_typ_str = f.read() rm_tmpd_and_files(tmpd) if v >= GenEvoConstants.V_DBG: print(" initializing workers ...", end="", flush=True) if use_local_mt: if v >= GenEvoConstants.V_DBG: print(" for local multiprocessing.") pool_size = cpu_count() pool = Pool(pool_size, GenEvoEvaluate.initialize_worker, [ simulation_cfg_str, trips_str, vtypes_str, plain_con_str, plain_edg_str, plain_nod_str, plain_tll_str, plain_typ_str, v ]) elif use_mpi: if v >= GenEvoConstants.V_DBG: print(" for mpi.") GenEvoEvaluate.initialize_worker(simulation_cfg_str, trips_str, vtypes_str, plain_con_str, plain_edg_str, plain_nod_str, plain_tll_str, plain_typ_str, v) glb_mpi = [("plain_con_m", GenEvoEvaluate.plain_con_g), ("plain_edg_m", GenEvoEvaluate.plain_edg_g), ("plain_nod_m", GenEvoEvaluate.plain_nod_g), ("plain_tll_m", GenEvoEvaluate.plain_tll_g), ("plain_typ_m", GenEvoEvaluate.plain_typ_g), ("sumo_cfg_m", GenEvoEvaluate.sumo_cfg_g), ("trips_m", GenEvoEvaluate.trips_g), ("vtypes_m", GenEvoEvaluate.vtypes_g), ("v_glb_m", GenEvoEvaluate.v_glb_g), ("netcnvt_m", GenEvoEvaluate.netcnvt_g), ("sumo_bin_m", GenEvoEvaluate.sumo_bin_g)] pool = futures.MPIPoolExecutor(globals=glb_mpi, main=True) pool.bootup(wait=True) del glb_mpi else: if v >= GenEvoConstants.V_DBG: print(" for single threading.") GenEvoEvaluate.initialize_worker(simulation_cfg_str, trips_str, vtypes_str, plain_con_str, plain_edg_str, plain_nod_str, plain_tll_str, plain_typ_str, v) pool = None del plain_files del plain_con_str del plain_edg_str del plain_nod_str del plain_tll_str del plain_typ_str del simulation_cfg_str del trips_str del vtypes_str ## genome = generate_genom_from_searchspace(searchspace) #possible gen only population_size - 1 individuals and inject a special individual with all genes do_nothing generation = initialize_first_generation(genome, population_size, stable_random, individual_id_ctr) individual_id_ctr += population_size evaluate_population(generation, op_mode, pool, timeout_s) generation_ctr = 0 fittest_individual = [generation[0], generation_ctr] for individual in generation: if individual[2] < fittest_individual[0][2]: fittest_individual = [individual, generation_ctr] if v >= GenEvoConstants.V_STAT: print( "Current generation is {}. Fittest individuals name is {} and it has a fitness value of {}." .format(generation_ctr, fittest_individual[0][0], fittest_individual[0][2])) netcnvt_bin = load_netconvert_binary() while generation_ctr < number_of_generations: if v >= GenEvoConstants.V_STAT: t_0 = time.monotonic() t_A_0 = t_0 generation = generate_new_generation(generation, population_size, genome, k_num, mutation_rate, stable_random, individual_id_ctr) individual_id_ctr += population_size / 2 if v >= GenEvoConstants.V_INF: t_1 = time.monotonic() print("Generation {} created in {}s.".format( generation_ctr + 1, t_1 - t_0)) t_E, t_M = evaluate_population(generation, op_mode, pool, timeout_s) if v >= GenEvoConstants.V_DBG: print("Evaluating the new individuals took {}s.".format(t_E)) if v >= GenEvoConstants.V_INF: print("Calculated fitness applied to individuals in {}s.".format( t_M)) generation_ctr += 1 if v >= GenEvoConstants.V_INF: t_0 = time.monotonic() fittest_individual_in_generation = [generation[0], generation_ctr] for individual in generation: if individual[2] < fittest_individual_in_generation[0][2]: fittest_individual_in_generation = [individual, generation_ctr] if fittest_individual_in_generation[0][2] < fittest_individual[0][2]: fittest_individual = fittest_individual_in_generation if not best_net_path is False: tmpd, best_plain_files = cnvt_net_to_plain( net_path, netcnvt_bin, "best", False) hack_for_cologne(best_plain_files) best_nr = Net_Repr(best_plain_files) GenEvoEvaluate.modify_net(fittest_individual[0], best_nr, best_plain_files, best_net_path, netcnvt_bin) rm_tmpd_and_files(tmpd) if v >= GenEvoConstants.V_INF: t_1 = time.monotonic() if v >= GenEvoConstants.V_STAT: print( "Current generation is {}. Fittest individuals name is {}, it has a fitness value of {}." .format(generation_ctr, fittest_individual_in_generation[0][0], fittest_individual_in_generation[0][2])) print( "Overall fittest individuals name is {}. It is from generation {} and has a fitness value of {}." .format(fittest_individual[0][0], fittest_individual[1], fittest_individual[0][2])) if v >= GenEvoConstants.V_INF: print("Fittest individual found in {}s.".format(t_1 - t_0)) if v >= GenEvoConstants.V_STAT: t_A_1 = time.monotonic() t_A = t_A_1 - t_A_0 print( "Generation took {}s, of which {}s where spend evaluating individuals and {}s managing the generation." .format(t_A, t_E, t_A - t_E)) if use_local_mt: pool.close() pool.join() elif use_mpi: pool.shutdown(wait=True) if not best_net_path is False: netcnvt_bin = load_netconvert_binary() tmpd, best_plain_files = cnvt_net_to_plain(net_path, netcnvt_bin, "best", False) hack_for_cologne(best_plain_files) best_nr = Net_Repr(best_plain_files) GenEvoEvaluate.modify_net(fittest_individual[0], best_nr, best_plain_files, best_net_path, netcnvt_bin) rm_tmpd_and_files(tmpd) t_t_1 = time.monotonic() if v >= GenEvoConstants.V_STAT: print("\n*** Result ***") print( "Tested {} individuals in {} generations. Best individual was {} from generation {} with fitness {}." .format(individual_id_ctr - 1, generation_ctr, fittest_individual[0][0], fittest_individual[1], fittest_individual[0][2])) print("Overall runtime {}s.".format(t_t_1 - t_t_0)) print("**************")