def run_experiment(params, vd_environment, trial_out_dir, num_dimensions, n_generations=100, 
                    save_results=False, silent=False, args=None):
    """
    The function to run the experiment against hyper-parameters 
    defined in the provided configuration file.
    The winner genome will be rendered as a graph as well as the
    important statistics of neuroevolution process execution.
    Arguments:
        params:             The NEAT parameters
        vd_environment:     The environment to test visual discrimination
        trial_out_dir:      The directory to store outputs for this trial
        num_dimensions:     The dimensionsionality of visual field
        n_generations:      The number of generations to execute.
        save_results:       The flag to control if intermdiate results will be saved.
        silent:             If True than no intermediary outputs will be
                            presented until solution is found.
        args:               The command line arguments holder.
    Returns:
        True if experiment finished with successful solver found. 
    """
    # random seed
    seed = int(time.time())

    # Create substrate
    substrate = create_substrate(num_dimensions)

    # Create CPPN genome and population
    g = NEAT.Genome(0,
                    substrate.GetMinCPPNInputs(),
                    0,
                    substrate.GetMinCPPNOutputs(),
                    False,
                    NEAT.ActivationFunction.UNSIGNED_SIGMOID,
                    NEAT.ActivationFunction.UNSIGNED_SIGMOID,
                    0,
                    params, 0)

    pop = NEAT.Population(g, params, True, 1.0, seed)
    pop.RNG.Seed(seed)

    # Run for up to N generations.
    start_time = time.time()
    best_genome_ser = None
    best_ever_goal_fitness = 0
    best_id = -1
    solution_found = False

    stats = Statistics()
    for generation in range(n_generations):
        print("\n****** Generation: %d ******\n" % generation)
        gen_time = time.time()
        # get list of current genomes
        genomes = NEAT.GetGenomeList(pop)

        # evaluate genomes
        genome, fitness, distances = eval_genomes(genomes, vd_environment=vd_environment, 
                                                substrate=substrate, generation=generation)

        stats.post_evaluate(max_fitness=fitness, distances=distances)
        solution_found = fitness >= FITNESS_THRESHOLD
        # store the best genome
        if solution_found or best_ever_goal_fitness < fitness:
            best_genome_ser = pickle.dumps(genome)
            best_ever_goal_fitness = fitness
            best_id = genome.GetID()
        
        if solution_found:
            print('Solution found at generation: %d, best fitness: %f, species count: %d' % (generation, fitness, len(pop.Species)))
            break

        # advance to the next generation
        pop.Epoch()

        # print statistics
        gen_elapsed_time = time.time() - gen_time
        print("Best fitness: %f, genome ID: %d" % (fitness, best_id))
        print("Species count: %d" % len(pop.Species))
        print("Generation elapsed time: %.3f sec" % (gen_elapsed_time))
        print("Best fitness ever: %f, genome ID: %d" % (best_ever_goal_fitness, best_id))

    elapsed_time = time.time() - start_time

    best_genome = pickle.loads(best_genome_ser)

    # write best genome to the file
    best_genome_file = os.path.join(trial_out_dir, "best_genome.pickle")
    with open(best_genome_file, 'wb') as genome_file:
        pickle.dump(best_genome, genome_file)

    # Print experiment statistics
    print("\nBest ever fitness: %f, genome ID: %d" % (best_ever_goal_fitness, best_id))
    print("\nTrial elapsed time: %.3f sec" % (elapsed_time))
    print("Random seed:", seed)

    # Visualize the experiment results
    show_results = not silent
    if save_results or show_results:
        # Draw CPPN network graph
        net = NEAT.NeuralNetwork()
        best_genome.BuildPhenotype(net)
        visualize.draw_net(net, view=show_results, node_names=None, directory=trial_out_dir, fmt='svg')
        print("\nCPPN nodes: %d, connections: %d" % (len(net.neurons), len(net.connections)))

         # Visualize activations from the best genome
        net = NEAT.NeuralNetwork()
        best_genome.BuildHyperNEATPhenotype(net, substrate)
        # select random visual field
        index = random.randint(0, len(vd_environment.data_set) - 1)
        print("\nRunning test evaluation against random visual field:", index)
        print("Substrate nodes: %d, connections: %d" % (len(net.neurons), len(net.connections)))
        vf = vd_environment.data_set[index]
        # draw activations
        outputs, x, y = vd_environment.evaluate_net_vf(net, vf)
        visualize.draw_activations(outputs, found_object=(x, y), vf=vf,
                                    dimns=num_dimensions, view=show_results, 
                                    filename=os.path.join(trial_out_dir, "best_activations.svg"))

        # Visualize statistics
        visualize.plot_stats(stats, ylog=False, view=show_results, filename=os.path.join(trial_out_dir, 'avg_fitness.svg'))

    return solution_found
def run_experiment(params,
                   rt_environment,
                   trial_out_dir,
                   n_generations=100,
                   save_results=False,
                   silent=False,
                   args=None):
    """
    The function to run the experiment against hyper-parameters 
    defined in the provided configuration file.
    The winner genome will be rendered as a graph as well as the
    important statistics of neuroevolution process execution.
    Arguments:
        params:             The NEAT parameters
        rt_environment:     The test environment for detector ANN evaluations
        trial_out_dir:      The directory to store outputs for this trial
        n_generations:      The number of generations to execute.
        save_results:       The flag to control if intermdiate results will be saved.
        silent:             If True than no intermediary outputs will be
                            presented until solution is found.
        args:               The command line arguments holder.
    Returns:
        True if experiment finished with successful solver found. 
    """
    # random seed
    seed = 1569777981  #int(time.time())

    # Create substrate
    substrate = create_substrate()

    # Create CPPN genome and population
    g = NEAT.Genome(
        0,
        substrate.GetMinCPPNInputs(),
        2,  # hidden units
        substrate.GetMinCPPNOutputs(),
        False,
        NEAT.ActivationFunction.TANH,
        NEAT.ActivationFunction.
        SIGNED_GAUSS,  # The initial activation type for hidden 
        1,  # hidden layers seed
        params,
        1)  # one hidden layer

    pop = NEAT.Population(g, params, True, 1.0, seed)
    pop.RNG.Seed(seed)

    # Run for up to N generations.
    start_time = time.time()
    best_genome_ser = None
    best_ever_goal_fitness = 0
    best_id = -1
    solution_found = False

    stats = Statistics()
    for generation in range(n_generations):
        print("\n****** Generation: %d ******\n" % generation)
        gen_time = time.time()
        # get list of current genomes
        genomes = NEAT.GetGenomeList(pop)

        # evaluate genomes
        genome, fitness, errors = eval_genomes(genomes,
                                               rt_environment=rt_environment,
                                               substrate=substrate,
                                               params=params)

        stats.post_evaluate(max_fitness=fitness, errors=errors)
        solution_found = fitness >= FITNESS_THRESHOLD
        # store the best genome
        if solution_found or best_ever_goal_fitness < fitness:
            best_genome_ser = pickle.dumps(
                genome)  # dump to pickle to freeze the genome state
            best_ever_goal_fitness = fitness
            best_id = genome.GetID()

        if solution_found:
            print(
                'Solution found at generation: %d, best fitness: %f, species count: %d'
                % (generation, fitness, len(pop.Species)))
            break

        # advance to the next generation
        pop.Epoch()

        # print statistics
        gen_elapsed_time = time.time() - gen_time
        print("Best fitness: %f, genome ID: %d" % (fitness, best_id))
        print("Species count: %d" % len(pop.Species))
        print("Generation elapsed time: %.3f sec" % (gen_elapsed_time))
        print("Best fitness ever: %f, genome ID: %d" %
              (best_ever_goal_fitness, best_id))

    # Find the experiment elapsed time
    elapsed_time = time.time() - start_time

    # Restore the freezed best genome from pickle
    best_genome = pickle.loads(best_genome_ser)

    # write best genome to the file
    best_genome_file = os.path.join(trial_out_dir, "best_genome.pickle")
    with open(best_genome_file, 'wb') as genome_file:
        pickle.dump(best_genome, genome_file)

    # Print experiment statistics
    print("\nBest ever fitness: %f, genome ID: %d" %
          (best_ever_goal_fitness, best_id))
    print("\nTrial elapsed time: %.3f sec" % (elapsed_time))
    print("Random seed:", seed)

    # Visualize the experiment results
    show_results = not silent
    if save_results or show_results:
        # Draw CPPN network graph
        net = NEAT.NeuralNetwork()
        best_genome.BuildPhenotype(net)
        visualize.draw_net(net,
                           view=False,
                           node_names=None,
                           filename="cppn_graph.svg",
                           directory=trial_out_dir,
                           fmt='svg')
        print("\nCPPN nodes: %d, connections: %d" %
              (len(net.neurons), len(net.connections)))

        # Draw the substrate network graph
        net = NEAT.NeuralNetwork()
        best_genome.BuildESHyperNEATPhenotype(net, substrate, params)
        visualize.draw_net(net,
                           view=False,
                           node_names=None,
                           filename="substrate_graph.svg",
                           directory=trial_out_dir,
                           fmt='svg')
        print("\nSubstrate nodes: %d, connections: %d" %
              (len(net.neurons), len(net.connections)))
        inputs = net.NumInputs()
        outputs = net.NumOutputs()
        hidden = len(net.neurons) - net.NumInputs() - net.NumOutputs()
        print("\n\tinputs: %d, outputs: %d, hidden: %d" %
              (inputs, outputs, hidden))

        # Test against random retina configuration
        l_index = random.randint(0, 15)
        r_index = random.randint(0, 15)
        left = rt_environment.visual_objects[l_index]
        right = rt_environment.visual_objects[r_index]
        err, outputs = rt_environment._evaluate(net, left, right, 3)
        print("Test evaluation error: %f" % err)
        print("Left flag: %f, pattern: %s" % (outputs[0], left))
        print("Right flag: %f, pattern: %s" % (outputs[1], right))

        # Test against all visual objects
        fitness, avg_error, total_count, false_detetctions = rt_environment.evaluate_net(
            net, debug=True)
        print(
            "Test evaluation against full data set [%d], fitness: %f, average error: %f, false detections: %f"
            % (total_count, fitness, avg_error, false_detetctions))

        # Visualize statistics
        visualize.plot_stats(stats,
                             ylog=False,
                             view=show_results,
                             filename=os.path.join(trial_out_dir,
                                                   'avg_fitness.svg'))

    return solution_found
def run_experiment(maze_env,
                   trial_out_dir,
                   args=None,
                   n_generations=100,
                   save_results=False,
                   silent=False):
    """
    The function to run the experiment against hyper-parameters 
    defined in the provided configuration file.
    The winner genome will be rendered as a graph as well as the
    important statistics of neuroevolution process execution.
    Arguments:
        maze_env:           The maze environment to use in simulation.
        trial_out_dir:      The directory to store outputs for this trial
        n_generations:      The number of generations to execute.
        save_results:       The flag to control if intermdiate results will be saved.
        silent:             If True than no intermediary outputs will be
                            presented until solution is found.
        args:               The command line arguments holder.
    Returns:
        True if experiment finished with successful solver found. 
    """
    # set random seed
    seed = int(time.time())  #1571021768#
    print("Random seed:           %d" % seed)

    # Create Population of Robots and objective functions
    robot = create_robot(maze_env, seed=seed)
    obj_func = create_objective_fun(seed)

    # Run for up to N generations.
    start_time = time.time()
    best_robot_genome_ser = None
    best_robot_id = -1
    solution_found = False
    best_obj_func_coeffs = None
    best_solution_novelty = 0
    best_solution_distance = 0

    stats = Statistics()
    for generation in range(n_generations):
        print("\n****** Generation: %d ******\n" % generation)
        gen_time = time.time()

        # evaluate objective function population
        obj_func_coeffs, max_obj_func_fitness = evaluate_obj_functions(
            obj_func, generation)

        # evaluate robots population
        robot_genome, solution_found, robot_fitness, distances, \
        obj_coeffs, best_distance, best_novelty = evaluate_solutions(
            robot=robot, obj_func_coeffs=obj_func_coeffs, generation=generation)

        stats.post_evaluate(max_fitness=robot_fitness, errors=distances)
        # store the best genome
        if solution_found or robot.population.GetBestFitnessEver(
        ) < robot_fitness:
            best_robot_genome_ser = pickle.dumps(robot_genome)
            best_robot_id = robot_genome.GetID()
            best_obj_func_coeffs = obj_coeffs
            best_solution_novelty = best_novelty
            best_solution_distance = best_distance

        if solution_found:
            print(
                '\nSolution found at generation: %d, best fitness: %f, species count: %d\n'
                % (generation, robot_fitness, len(robot.population.Species)))
            break

        # advance to the next generation
        robot.population.Epoch()
        obj_func.population.Epoch()

        # print statistics
        gen_elapsed_time = time.time() - gen_time
        print("Generation fitness -> solution: %f, objective function: %f" %
              (robot_fitness, max_obj_func_fitness))
        print(
            "Gen. species count -> solution: %d, objective function: %d" %
            (len(robot.population.Species), len(obj_func.population.Species)))
        print("Gen. archive size  -> solution: %d, objective function: %d" %
              (robot.archive.size(), obj_func.archive.size()))
        print("Objective function coeffts:     %s" % obj_coeffs)
        print(
            "Gen. best solution genome ID:   %d, distance to exit: %f, novelty: %f"
            % (robot_genome.GetID(), best_distance, best_novelty))
        print("->")
        print("Best fitness ever  -> solution: %f, objective function: %f" %
              (robot.population.GetBestFitnessEver(),
               obj_func.population.GetBestFitnessEver()))
        print(
            "Best ever solution genome ID:   %d, distance to exit: %f, novelty: %f"
            % (best_robot_id, best_solution_distance, best_solution_novelty))
        print("------------------------------")
        print("Generation elapsed time:        %.3f sec\n" %
              (gen_elapsed_time))

    elapsed_time = time.time() - start_time
    # Load serialized best robot genome
    best_robot_genome = pickle.loads(best_robot_genome_ser)

    # write best genome to the file
    best_genome_file = os.path.join(trial_out_dir, "best_robot_genome.pickle")
    with open(best_genome_file, 'wb') as genome_file:
        pickle.dump(best_robot_genome, genome_file)

    # write the record store data
    rs_file = os.path.join(trial_out_dir, "data.pickle")
    robot.record_store.dump(rs_file)

    print("==================================")
    print("Record store file:     %s" % rs_file)
    print("Random seed:           %d" % seed)
    print("............")
    print("Best solution fitness: %f, genome ID: %d" %
          (robot.population.GetBestFitnessEver(), best_robot_genome.GetID()))
    print("Best objective func coefficients: %s" % best_obj_func_coeffs)
    print("------------------------------")

    # Visualize the experiment results
    show_results = not silent
    if save_results or show_results:
        if args is None:
            visualize.draw_maze_records(maze_env,
                                        robot.record_store.records,
                                        view=show_results)
        else:
            visualize.draw_maze_records(maze_env,
                                        robot.record_store.records,
                                        view=show_results,
                                        width=args.width,
                                        height=args.height,
                                        filename=os.path.join(
                                            trial_out_dir, 'maze_records.svg'))
        # store NoveltyItems archive data
        robot.archive.write_to_file(
            path=os.path.join(trial_out_dir, 'ns_items_all.txt'))

        # create the best genome simulation path and render
        maze_env = copy.deepcopy(robot.orig_maze_environment)
        multi_net = NEAT.NeuralNetwork()
        best_robot_genome.BuildPhenotype(multi_net)
        depth = 8
        try:
            best_robot_genome.CalculateDepth()
            depth = genome.GetDepth()
        except:
            pass
        control_net = ANN(multi_net, depth=depth)
        path_points = []
        distance = maze.maze_simulation_evaluate(env=maze_env,
                                                 net=control_net,
                                                 time_steps=SOLVER_TIME_STEPS,
                                                 path_points=path_points)
        print("Best solution distance to maze exit: %.2f, novelty: %.2f" %
              (distance, best_solution_novelty))
        visualize.draw_agent_path(robot.orig_maze_environment,
                                  path_points,
                                  best_robot_genome,
                                  view=show_results,
                                  width=args.width,
                                  height=args.height,
                                  filename=os.path.join(
                                      trial_out_dir, 'best_solver_path.svg'))

        # Draw the best agent phenotype ANN
        visualize.draw_net(multi_net,
                           view=show_results,
                           filename="best_solver_net",
                           directory=trial_out_dir)

        # Visualize statistics
        visualize.plot_stats(stats,
                             ylog=False,
                             view=show_results,
                             filename=os.path.join(trial_out_dir,
                                                   'avg_fitness.svg'))

    print("------------------------")
    print("Trial elapsed time:    %.3f sec" % (elapsed_time))
    print("==================================")

    return solution_found