Index: framspy/evolalg/examples/invalid.py
===================================================================
--- framspy/evolalg/examples/invalid.py	(revision 1129)
+++ 	(revision )
@@ -1,114 +1,0 @@
-import random
-
-import argparse
-import os
-import sys
-import numpy as np
-
-from evolalg.base.lambda_step import LambdaStep
-from evolalg.experiment import Experiment
-from evolalg.fitness.fitness_step import FitnessStep
-from evolalg.mutation_cross.frams_cross_and_mutate import FramsCrossAndMutate
-from evolalg.population.frams_population import FramsPopulation
-from evolalg.repair.multistep import MultistepRepair
-from evolalg.repair.remove.field import FieldRemove
-from evolalg.selection.tournament import TournamentSelection
-from evolalg.statistics.halloffame_stats import HallOfFameStatistics
-from evolalg.statistics.statistics_deap import StatisticsDeap
-from evolalg.base.union_step import UnionStep
-from evolalg.utils.population_save import PopulationSave
-from evolalg.utils.stable_generation import StableGeneration
-from FramsticksLib import FramsticksLib
-
-
-def ensureDir(string):
-    if os.path.isdir(string):
-        return string
-    else:
-        raise NotADirectoryError(string)
-
-
-def parseArguments():
-    parser = argparse.ArgumentParser(
-        description='Run this program with "python -u %s" if you want to disable buffering of its output.' % sys.argv[
-            0])
-    parser.add_argument('-path', type=ensureDir, required=True, help='Path to Framsticks without trailing slash.')
-    # parser.add_argument('-opt', required=True,
-    #                     help='optimization criteria : vertpos, velocity, distance, vertvel, lifespan, numjoints, numparts, numneurons, numconnections. Single or multiple criteria.')
-    parser.add_argument('-lib', required=False, help="Filename of .so or .dll with framsticks library")
-    parser.add_argument('-genformat', required=False, default="1",
-                        help='Genetic format for the demo run, for example 4, 9, or B. If not given, f1 is assumed.')
-
-    parser.add_argument("-popsize", type=int, default=50, help="Size of population, default 50.")
-    return parser.parse_args()
-
-
-def extract_fitness(ind):
-    return ind.fitness
-
-
-def print_population_count(pop):
-    print("Current:",len(pop))
-    return pop # Each step must return a population
-
-
-def random_remove(pop):
-    return [_ for _ in pop if random.randint(0, 1) == 0]
-
-
-def main():
-    parsed_args = parseArguments()
-    frams_lib = FramsticksLib(parsed_args.path, parsed_args.lib, "eval-movement.sim")
-
-    hall_of_fame = HallOfFameStatistics(100, "fitness")
-    statistics_union = UnionStep([
-        hall_of_fame,
-        StatisticsDeap([
-            ("avg", np.mean),
-            ("stddev", np.std),
-            ("min", np.min),
-            ("max", np.max),
-            ("count", len)
-        ], extract_fitness)
-    ])
-
-    fitness_remove = UnionStep([
-        FitnessStep(frams_lib, fields={"velocity": "fitness", "data->recording": "recording"},
-                    fields_defaults={"velocity": None, "data->recording": None}),
-        FieldRemove("recording", None),
-        print_population_count,  # Stages can be also any Callable
-    ])
-
-    selection = TournamentSelection(5, copy=True)
-    new_generation_steps = [
-        FramsCrossAndMutate(frams_lib, cross_prob=0.2, mutate_prob=0.9),
-        fitness_remove
-    ]
-
-    generation_modifications = [
-        statistics_union  # Or niching, novelty
-    ]
-
-    init_stages = [FramsPopulation(frams_lib, parsed_args.genformat, parsed_args.popsize),
-                   fitness_remove,  # It is possible to create smaller population
-                   statistics_union]
-
-    end_steps = [PopulationSave("halloffame.gen", provider=hall_of_fame.halloffame, fields={"genotype": "genotype",
-                                                                                           "fitness": "fitness",
-                                                                                           "custom": "recording"})]
-
-    experiment = Experiment(init_population=init_stages,
-                            selection=selection,
-                            new_generation_steps=new_generation_steps,
-                            generation_modification=generation_modifications,
-                            end_steps=end_steps,
-                            population_size=parsed_args.popsize
-                            )
-    experiment.init()
-    experiment.run(3)
-    for ind in hall_of_fame.halloffame:
-        print("%g\t%s" % (ind.fitness, ind.genotype))
-
-
-if __name__ == '__main__':
-    main()
Index: framspy/evolalg/examples/standard.py
===================================================================
--- framspy/evolalg/examples/standard.py	(revision 1129)
+++ framspy/evolalg/examples/standard.py	(revision 1131)
@@ -4,21 +4,29 @@
 import numpy as np
 
-#TODO add new example: steadystate.py (analogous to standard.py)
+#TODO add new example: steadystate.py (analogous to standard.py) OR include steadysteate as a mode in this example or in niching_novelty.py
 #TODO extend both standard.py and steadystate.py to support >1 criteria (using DEAP's selNSGA2() and selSPEA2())
 #TODO add comments to all examples in this directory
-#TODO add to standard.py and steadystate.py evaluating each genotype in HOF N (configurable, default 10) times when the evolution ends
+#TODO add to standard.py and steadystate.py evaluating each genotype in HOF N (configurable, default 10) times when the evolution ends instead of evaluating the last population as it is now in niching_novelty.py
 #TODO protect all examples against invalid genotypes (fill population until all genotypes are conrrectly evaluated). And maybe remove invalid.py if it overlaps with (is a subset of) other examples
+#TODO "debug" mode, displaying Step-based class names and their arguments so it is easy to see what happens during evolution
 
-from FramsticksLib import FramsticksLib
 from evolalg.base.lambda_step import LambdaStep
-from evolalg.dissimilarity.frams_dissimilarity import FramsDissimilarity
 from evolalg.experiment import Experiment
 from evolalg.fitness.fitness_step import FitnessStep
 from evolalg.mutation_cross.frams_cross_and_mutate import FramsCrossAndMutate
 from evolalg.population.frams_population import FramsPopulation
+from evolalg.repair.multistep import MultistepRepair
+from evolalg.repair.remove.field import FieldRemove
 from evolalg.selection.tournament import TournamentSelection
 from evolalg.statistics.halloffame_stats import HallOfFameStatistics
 from evolalg.statistics.statistics_deap import StatisticsDeap
 from evolalg.base.union_step import UnionStep
+from evolalg.utils.population_save import PopulationSave
+from evolalg.utils.stable_generation import StableGeneration
+from FramsticksLib import FramsticksLib
+
+
+
+EVAL_LIFESPAN_BEHAVIOR = False  # if False, standard evaluation criteria can be used as fitness as defined by the -opt parameter. If True, it is assumed that the expdef provides custom dictionary fields in evaluation and they need to be handled specifically in python source code below (this could be parametrized in command-line too, but the syntax would be complex)
 
 
@@ -34,11 +42,11 @@
         description='Run this program with "python -u %s" if you want to disable buffering of its output.' % sys.argv[
             0])
-    parser.add_argument('-path', type=ensureDir, required=True, help='Path to Framsticks without trailing slash.')
+    parser.add_argument('-path', type=ensureDir, required=True, help='Path to the Framsticks library without trailing slash.')
     parser.add_argument('-opt', required=True,
-                        help='optimization criteria : vertpos, velocity, distance, vertvel, lifespan, numjoints, numparts, numneurons, numconnections. Single or multiple criteria.')
-    parser.add_argument('-lib', required=False, help="Filename of .so or .dll with framsticks library")
+                        help='optimization criteria : vertpos, velocity, distance, vertvel, lifespan, numjoints, numparts, numneurons, numconnections (or other as long as it is provided by the .sim file and its .expdef). Single or multiple criteria.')
+    parser.add_argument('-lib', required=False, help="Filename of .so or .dll with the Framsticks library")
     parser.add_argument('-genformat', required=False, default="1",
                         help='Genetic format for the demo run, for example 4, 9, or B. If not given, f1 is assumed.')
-
+    parser.add_argument('-sim', required=False, default="eval-allcriteria.sim", help="Name of the .sim file with all parameter values")
     parser.add_argument("-popsize", type=int, default=50, help="Population size, default 50.")
     parser.add_argument('-generations', type=int, default=5, help="Number of generations, default 5.")
@@ -58,6 +66,5 @@
 def main():
     parsed_args = parseArguments()
-    frams = FramsticksLib(parsed_args.path, parsed_args.lib,
-                          "eval-allcriteria.sim")
+    frams_lib = FramsticksLib(parsed_args.path, parsed_args.lib, parsed_args.sim)
 
     hall_of_fame = HallOfFameStatistics(100, "fitness")
@@ -73,20 +80,36 @@
     ])
 
-    fitness = FitnessStep(frams, fields={parsed_args.opt: "fitness", }, fields_defaults={})
-
-    init_stages = [FramsPopulation(frams, parsed_args.genformat, 50),
-                   fitness,
-                   statistics_union]
+    fitness_remove = UnionStep(
+        [
+        FitnessStep(frams_lib, fields={"velocity": "fitness", "data->recording": "recording"},
+                    fields_defaults={"velocity": None, "data->recording": None})  # custom definitions and handling
+        if EVAL_LIFESPAN_BEHAVIOR else
+        FitnessStep(frams_lib, fields={parsed_args.opt: "fitness", }, fields_defaults={})
+        ]
+        +
+        ([FieldRemove("recording", None)] if EVAL_LIFESPAN_BEHAVIOR else [])
+        +
+        [print_population_count]  # Stages can also be any Callable
+    )
 
     selection = TournamentSelection(parsed_args.tournament, copy=True, fit_attr="fitness")
-
     new_generation_steps = [
-        FramsCrossAndMutate(frams, cross_prob=0.2, mutate_prob=0.9),
-        fitness,
+        FramsCrossAndMutate(frams_lib, cross_prob=0.2, mutate_prob=0.9),
+        fitness_remove
     ]
 
     generation_modifications = [
-        statistics_union
+        statistics_union  # Or niching, novelty
     ]
+
+    init_stages = [FramsPopulation(frams_lib, parsed_args.genformat, parsed_args.popsize),
+                   fitness_remove,  # It is possible to create smaller population
+                   statistics_union]
+
+    end_steps = [PopulationSave("halloffame.gen", provider=hall_of_fame.halloffame,
+                                fields={"genotype": "genotype", "fitness": "fitness", "custom": "recording"}
+                                if EVAL_LIFESPAN_BEHAVIOR
+                                else {"genotype": "genotype", "fitness": "fitness"}
+                                )]
 
     experiment = Experiment(init_population=init_stages,
@@ -94,5 +117,5 @@
                             new_generation_steps=new_generation_steps,
                             generation_modification=generation_modifications,
-                            end_steps=[],
+                            end_steps=end_steps,
                             population_size=parsed_args.popsize
                             )
