def iterate(MachineClass, stop_function=lambda iterations: iterations < 10000,
        machines=1000, survival_rate=0.05, mutation_rate=0.075, silent=False):
    def make_random(n):
        return MachineClass().randomize()
    def run_once(m):
        m.setUp()
        m.run()
        m.tearDown()
        return m
    def make_offspring(survivors):
        a = stochastic_choice(survivors)
        b = stochastic_choice(survivors)
        return a.crossover(b)
    generation = map(make_random, xrange(machines))
    survivors = generation
    if silent:
        log = lambda s,stream=None: None
    else:
        log = _log
    try:
        iterations = 0
        while not stop_function(iterations, survivors):
            iterations += 1
            log("running ... ")
            generation = map(run_once, generation)
            generation = sorted(generation, key=lambda m: m.score())
            survivors = generation[:int(survival_rate * len(generation))]
            for s in survivors:
                if len(s.code) >= 50:
                    s.code = s.code[:50]
            survivors = [s for s in survivors if len(s.code)>0]
            if len(survivors) == 0:
                log("\nNo survivors, restarting")
                survivors = map(make_random, xrange(machines))
                generation = survivors
                continue
            log("crossover ... ")
            cross = lambda _: make_offspring(survivors)
            generation = map(cross, xrange(machines))
            for m in generation:
                if random.random() > mutation_rate:
                    m.mutate()
            log("\rgen %d 1-fitness %.12f avg code len %.2f avg stack len %.2f\n" %
                (iterations,
                 average(survivors, lambda m: m.score()),
                 average(survivors, lambda m: len(m.code)),
                 average(survivors, lambda m: len(m.stack) + len(m.return_stack))))
    except KeyboardInterrupt:
        pass
    return survivors