<commit_before>from collections import deque
import copy
import heapq

from edge import DummyEdgeEnd

class AbstractSimulationEvent(object):
    def process_start(self):
        return frozenset()
    def process_end(self, world, stats):
        return frozenset()

class PheromoneVaporization(AbstractSimulationEvent):
    MULTIPLIER = 0.8
    PERIOD = 100
    TRIGGER_LEVEL = 100
    def __init__(self, end_time, ant_count):
        self.end_time = end_time
        self.ant_count = ant_count
    def process_end(self, world, stats):
        changed = []
        max_pheromone = world.get_max_pheromone_level()
        if max_pheromone >= self.TRIGGER_LEVEL:
            for edge in world.edges:
                for edge_end in (edge.a_end, edge.b_end):
                    new = max(0.0, edge_end.pheromone_level*self.MULTIPLIER)
                    if edge_end.pheromone_level!=new:
                        changed.append(edge_end.edge)
                        edge_end.pheromone_level = new
        return PheromoneVaporization(self.end_time+self.PERIOD, self.ant_count), frozenset(changed)

class AbstractAntMove(AbstractSimulationEvent):
    def __init__(self, ant, origin, destination, end_time, pheromone_to_drop, trip_stats):
        self.ant = ant
        self.origin = origin
        self.destination = destination
        if self.origin is not None and self.destination is not None:
            if self.origin.edge is not None and self.destination.edge is not None:
                #print 'origin', self.origin
                #print 'destination', self.destination
                assert self.origin.edge == self.destination.edge
        self.end_time = end_time
        self.pheromone_to_drop = pheromone_to_drop
        self.trip_stats = trip_stats
    def process_start(self):
        self.origin.drop_pheromone(self.pheromone_to_drop)
        #print "1 dropping %s pheromone on %s" % (self.pheromone_to_drop, self.origin)
        return frozenset((self.origin.edge, self.origin.point))
    def process_end(self, world, stats):
        changed = [self.destination.edge]
        self.trip_stats.edge_visited(self.destination.edge)
        self.destination.drop_pheromone(self.pheromone_to_drop)
        #print "2 dropping %s pheromone on %s" % (self.pheromone_to_drop, self.destination)
        if not self.destination.point.is_anthill() and self.destination.point.food > 0 and not self.ant.food:
            changed.append(self.destination.point)
            self.trip_stats.food_found()
            self.destination.point.food -= 1
            self.ant.food += 1
            stats.food_found(self.trip_stats)
            stats.present()
        elif self.destination.point.is_anthill():
            if self.ant.food:
                changed.append(self.destination.point)
                self.destination.point.food += self.ant.food
                self.trip_stats.back_home()
                new_ant = self.ant.__class__(self.ant.world_parameters)
                return AntRestartMove(new_ant, anthill=DummyEdgeEnd(self.destination.point), end_time=world.elapsed_time), frozenset(changed)
            else:
                self.trip_stats.reset_route()
        new_destination_edge, pheromone_to_drop = self.ant.tick(self.destination.point)
        assert new_destination_edge in (end.edge for end in self.destination.point.edge_ends), 'Illegal ant move'
        self.trip_stats.normal_move(new_destination_edge.cost)
        new_destination = new_destination_edge.get_other_end_by_point(self.destination.point)
        origin = new_destination_edge.get_other_end(new_destination)
        end_time = world.elapsed_time + new_destination_edge.cost
        return AntMove(
            ant=self.ant,
            origin=origin,
            destination=new_destination,
            end_time=end_time,
            pheromone_to_drop=pheromone_to_drop,
            trip_stats=self.trip_stats,
        ), frozenset(changed)
    def __cmp__(self, other):
        return self.end_time - other.end_time
    def __repr__(self):
        return '%s@%s' % (self.__class__.__name__, self.end_time,)

class AntRestartMove(AbstractAntMove):
    def __init__(self, ant, anthill, end_time):
        super(AntRestartMove, self).__init__(ant, None, anthill, end_time=end_time, pheromone_to_drop=0, trip_stats=TripStats())
    def process_start(self):
        return frozenset()

class AntStartMove(AntRestartMove):
    def __init__(self, ant, anthill):
        super(AntStartMove, self).__init__(ant, anthill, end_time=0)

class AntMove(AbstractAntMove):
    pass

class TripStats(object):
    def __init__(self):
        self.food_found_after = 0, 0
        self.total_cost = 0
        self.total_moves = 0
        self.visited = deque()
    def reset_route(self):
        self.visited = deque()
    def food_found(self):
        self.food_found_after = self.total_moves, self.total_cost
    def normal_move(self, cost):
        self.total_moves += 1
        self.total_cost += cost
    def edge_visited(self, edge):
        self.visited.append(edge)
    def back_home(self):
        #print 'moves: %s, cost: %s, to find: %s' % (self.total_moves, self.total_cost, self.food_found_after)
        pass

class QueenStats(object):
    def __init__(self, reality, number_of_ants):
        self.reality = reality
        self.food_discovered = 0
        self.moves_leading_to_food_being_found = 0
        self.number_of_ants = number_of_ants
        self.best_finding_cost = 999999999
        self.last_cost = 0
        self.last_route = []
    def food_found(self, trip_stats):
        self.food_discovered += 1
        self.last_cost = trip_stats.food_found_after[1]
        self.moves_leading_to_food_being_found += trip_stats.food_found_after[0]
        self.best_finding_cost = min(self.best_finding_cost, trip_stats.food_found_after[1])
        self.last_route = copy.copy(trip_stats.visited)
    def present(self):
        avg_cost = (self.reality.world.elapsed_time*self.number_of_ants)/self.food_discovered
        avg_moves = self.moves_leading_to_food_being_found/self.food_discovered
        avg_pheromone = self.reality.world.get_average_pheromone_level()
        print 'food found: %d, best: %.3f, avg. pheromone: %.3f, avg. moves to find: %d, avg. cost to find: %.3f, time: %d, last_cost: %s' % (self.food_discovered, self.best_finding_cost, avg_pheromone, avg_moves, avg_cost, self.reality.world.elapsed_time, self.last_cost)

class AbstractSimulation(object):
    def __init__(self, reality, antmoves, stats):
        self.reality = reality
        self.antmoves = antmoves
        heapq.heapify(antmoves)
        self.stats = stats
        self.ticks = 0
    def tick(self):
        ant_move = heapq.heappop(self.antmoves)
        self.reality.world.elapsed_time = ant_move.end_time # simulation is now at the point of ant_move.ant arriving at ant_move.destination
        #print 'processing ant_move', ant_move.end_time
        #print '[%f] %s is moving to %s, %s' % (self.reality.world.elapsed_time, ant_move.ant, ant_move.destination.point, ant_move.ant.food)
        #print sum([food_point.food for food_point in self.reality.world.get_food_points()])
        new_antmove, changed_items_end = ant_move.process_end(self.reality.world, self.stats)
        assert not self.reality.world.elapsed_time > ant_move.end_time
        changed_items_start = new_antmove.process_start()
        assert changed_items_start is not None, new_antmove
        heapq.heappush(self.antmoves, new_antmove)
        self.ticks += 1
        return changed_items_start & changed_items_end, self.stats

class TickStepSimulation(AbstractSimulation):
    def advance(self):
        print 'ticks', self.ticks
        if self.reality.is_resolved():
            return [], True, None
        tick_changed_items, stats = self.tick()
        return tick_changed_items, False, stats.last_route

class MultiSpawnStepSimulation(AbstractSimulation):
    def __init__(self, reality, *args, **kwargs):
        super(MultiSpawnStepSimulation, self).__init__(reality, *args, **kwargs)
        self.spawn_amount = 100<commit_msg>Increase frame rendering frequency in MultiSpawn mode<commit_after>from collections import deque
import copy
import heapq

from edge import DummyEdgeEnd

class AbstractSimulationEvent(object):
    def process_start(self):
        return frozenset()
    def process_end(self, world, stats):
        return frozenset()

class PheromoneVaporization(AbstractSimulationEvent):
    MULTIPLIER = 0.8
    PERIOD = 100
    TRIGGER_LEVEL = 100
    def __init__(self, end_time, ant_count):
        self.end_time = end_time
        self.ant_count = ant_count
    def process_end(self, world, stats):
        changed = []
        max_pheromone = world.get_max_pheromone_level()
        if max_pheromone >= self.TRIGGER_LEVEL:
            for edge in world.edges:
                for edge_end in (edge.a_end, edge.b_end):
                    new = max(0.0, edge_end.pheromone_level*self.MULTIPLIER)
                    if edge_end.pheromone_level!=new:
                        changed.append(edge_end.edge)
                        edge_end.pheromone_level = new
        return PheromoneVaporization(self.end_time+self.PERIOD, self.ant_count), frozenset(changed)

class AbstractAntMove(AbstractSimulationEvent):
    def __init__(self, ant, origin, destination, end_time, pheromone_to_drop, trip_stats):
        self.ant = ant
        self.origin = origin
        self.destination = destination
        if self.origin is not None and self.destination is not None:
            if self.origin.edge is not None and self.destination.edge is not None:
                #print 'origin', self.origin
                #print 'destination', self.destination
                assert self.origin.edge == self.destination.edge
        self.end_time = end_time
        self.pheromone_to_drop = pheromone_to_drop
        self.trip_stats = trip_stats
    def process_start(self):
        self.origin.drop_pheromone(self.pheromone_to_drop)
        #print "1 dropping %s pheromone on %s" % (self.pheromone_to_drop, self.origin)
        return frozenset((self.origin.edge, self.origin.point))
    def process_end(self, world, stats):
        changed = [self.destination.edge]
        self.trip_stats.edge_visited(self.destination.edge)
        self.destination.drop_pheromone(self.pheromone_to_drop)
        #print "2 dropping %s pheromone on %s" % (self.pheromone_to_drop, self.destination)
        if not self.destination.point.is_anthill() and self.destination.point.food > 0 and not self.ant.food:
            changed.append(self.destination.point)
            self.trip_stats.food_found()
            self.destination.point.food -= 1
            self.ant.food += 1
            stats.food_found(self.trip_stats)
            stats.present()
        elif self.destination.point.is_anthill():
            if self.ant.food:
                changed.append(self.destination.point)
                self.destination.point.food += self.ant.food
                self.trip_stats.back_home()
                new_ant = self.ant.__class__(self.ant.world_parameters)
                return AntRestartMove(new_ant, anthill=DummyEdgeEnd(self.destination.point), end_time=world.elapsed_time), frozenset(changed)
            else:
                self.trip_stats.reset_route()
        new_destination_edge, pheromone_to_drop = self.ant.tick(self.destination.point)
        assert new_destination_edge in (end.edge for end in self.destination.point.edge_ends), 'Illegal ant move'
        self.trip_stats.normal_move(new_destination_edge.cost)
        new_destination = new_destination_edge.get_other_end_by_point(self.destination.point)
        origin = new_destination_edge.get_other_end(new_destination)
        end_time = world.elapsed_time + new_destination_edge.cost
        return AntMove(
            ant=self.ant,
            origin=origin,
            destination=new_destination,
            end_time=end_time,
            pheromone_to_drop=pheromone_to_drop,
            trip_stats=self.trip_stats,
        ), frozenset(changed)
    def __cmp__(self, other):
        return self.end_time - other.end_time
    def __repr__(self):
        return '%s@%s' % (self.__class__.__name__, self.end_time,)

class AntRestartMove(AbstractAntMove):
    def __init__(self, ant, anthill, end_time):
        super(AntRestartMove, self).__init__(ant, None, anthill, end_time=end_time, pheromone_to_drop=0, trip_stats=TripStats())
    def process_start(self):
        return frozenset()

class AntStartMove(AntRestartMove):
    def __init__(self, ant, anthill):
        super(AntStartMove, self).__init__(ant, anthill, end_time=0)

class AntMove(AbstractAntMove):
    pass

class TripStats(object):
    def __init__(self):
        self.food_found_after = 0, 0
        self.total_cost = 0
        self.total_moves = 0
        self.visited = deque()
    def reset_route(self):
        self.visited = deque()
    def food_found(self):
        self.food_found_after = self.total_moves, self.total_cost
    def normal_move(self, cost):
        self.total_moves += 1
        self.total_cost += cost
    def edge_visited(self, edge):
        self.visited.append(edge)
    def back_home(self):
        #print 'moves: %s, cost: %s, to find: %s' % (self.total_moves, self.total_cost, self.food_found_after)
        pass

class QueenStats(object):
    def __init__(self, reality, number_of_ants):
        self.reality = reality
        self.food_discovered = 0
        self.moves_leading_to_food_being_found = 0
        self.number_of_ants = number_of_ants
        self.best_finding_cost = 999999999
        self.last_cost = 0
        self.last_route = []
    def food_found(self, trip_stats):
        self.food_discovered += 1
        self.last_cost = trip_stats.food_found_after[1]
        self.moves_leading_to_food_being_found += trip_stats.food_found_after[0]
        self.best_finding_cost = min(self.best_finding_cost, trip_stats.food_found_after[1])
        self.last_route = copy.copy(trip_stats.visited)
    def present(self):
        avg_cost = (self.reality.world.elapsed_time*self.number_of_ants)/self.food_discovered
        avg_moves = self.moves_leading_to_food_being_found/self.food_discovered
        avg_pheromone = self.reality.world.get_average_pheromone_level()
        print 'food found: %d, best: %.3f, avg. pheromone: %.3f, avg. moves to find: %d, avg. cost to find: %.3f, time: %d, last_cost: %s' % (self.food_discovered, self.best_finding_cost, avg_pheromone, avg_moves, avg_cost, self.reality.world.elapsed_time, self.last_cost)

class AbstractSimulation(object):
    def __init__(self, reality, antmoves, stats):
        self.reality = reality
        self.antmoves = antmoves
        heapq.heapify(antmoves)
        self.stats = stats
        self.ticks = 0
    def tick(self):
        ant_move = heapq.heappop(self.antmoves)
        self.reality.world.elapsed_time = ant_move.end_time # simulation is now at the point of ant_move.ant arriving at ant_move.destination
        #print 'processing ant_move', ant_move.end_time
        #print '[%f] %s is moving to %s, %s' % (self.reality.world.elapsed_time, ant_move.ant, ant_move.destination.point, ant_move.ant.food)
        #print sum([food_point.food for food_point in self.reality.world.get_food_points()])
        new_antmove, changed_items_end = ant_move.process_end(self.reality.world, self.stats)
        assert not self.reality.world.elapsed_time > ant_move.end_time
        changed_items_start = new_antmove.process_start()
        assert changed_items_start is not None, new_antmove
        heapq.heappush(self.antmoves, new_antmove)
        self.ticks += 1
        return changed_items_start & changed_items_end, self.stats

class TickStepSimulation(AbstractSimulation):
    def advance(self):
        print 'ticks', self.ticks
        if self.reality.is_resolved():
            return [], True, None
        tick_changed_items, stats = self.tick()
        return tick_changed_items, False, stats.last_route

class MultiSpawnStepSimulation(AbstractSimulation):
    def __init__(self, reality, *args, **kwargs):
        super(MultiSpawnStepSimulation, self).__init__(reality, *args, **kwargs)
        self.spawn_amount = 50
{'fraction_non_alphanumeric': 0.09394816228529212, 'fraction_numerical': 0.0056024133472880626, 'mean_word_length': 2.909506618531889, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1740987', 'n_tokens_mistral': 5242, 'n_tokens_neox': 5096, 'n_words': 987}