Exemple #1
0
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("**************")