<commit_before>"""
The topographica simulator module.  

The Simulator object is the central object of a Topographica
simulation.  It handles the simulation clock and maintains
communication between the components of the simulation.

A simulation is structured as a directed graph of event-processing nodes
called EventProcessors (EPs).  EventProcessors generate data-carrying
events, which are routed through the graph to other EventProcessors
via delayed connections.

The simulator is modular: EventProcessors should inherit from the root
EventProcessor class.  This class manages the EP's connections to
other EPs, as well as the mechanics of sending events to other EPs
(through the simulator).  The EventProcessor class defines the basic
EP programming interface.

Formally, a simulation event is a tuple:
(time,src,src_port,dest,dest_port,data), where

  time      = The time at which the event should be delivered, an arbitrary
              floating point value.
  src       = The EventProcessor from which the event originated.
  src_port  = The output port from which the event originated
              in the source EP. (see PORTS, below)
  dest      = Destination EventProcessor of the event
  dest_port = The input port to which the event is destined in dest.
              (see PORTS) below.
  data      = The event data to be delivered.  Can be anything.


A simulation begins by giving each EventProcessor an opportunity to
send any initial events.  It then proceeds by processing and
delivering events to EventProcessors in time order.  After all events
for the current time are processed, the simulator gives each
EventProcessor a chance to do any final computation, after which
simulation time skips to the time of the earliest event remaining in
the queue.

PORTS

All connections between EPs are tagged with a source port and a
destination port.  Ports are internal addresses that EPs can use to
distinguish between inputs and outputs.  A port specifier can be any
hashable Python object.  If not specified, the input and output ports
for a connection default to None.

Output ports distinguish different types of output that an EP may
produce. When sending output, the EP must call self.send_output()
separately for each port.  Input ports distinguish different types of
input an EP may receive and process.  The EP is free to interpret the
input port designation on an incoming event in any way it chooses.

An example of input port use might be an EP that receives 'ordinary'
neural activity on the default port, and receives a separate
modulatory signal that influences learning.  The originator of the
modulatory signal might have a connection to the EP with dest_port =
'modulation'.

An example of output port use might be an EP that sends different
events to itself than it sends out to other EPs.  In this case the
self connections might have src_port = 'recurrent'.


Current Simulator

The current Simulator, which can be accessed through the instance
of the Singleton class SimSingleton(), is the last Simulator to
have been created with register=True (the default).


$Id$
"""
__version__='$Revision$'

from parameterizedobject import ParameterizedObject, Parameter
from parameterclasses import Number, BooleanParameter, CallableParameter
from copy import copy, deepcopy
from fixedpoint import FixedPoint

SLEEP_EXCEPTION = "Sleep Exception"
STOP = "Simulator Stopped"

Forever = FixedPoint(-1)


# CEBHACKALERT: this is to be removed; calls
# can be replaced by 'topo.sim'

def get_active_sim():
    """
    Return the active simulator.
    """
    return SimSingleton()


class Singleton(object):
    """
    The singleton pattern.

    To create a singleton class, you subclass from Singleton; each
    subclass will have a single instance, no matter how many times its
    constructor is called. To further initialize the subclass
    instance, subclasses should override 'init' instead of __init__ -
    the __init__ method is called each time the constructor is called.

    From http://www.python.org/2.2.3/descrintro.html#__new__
    """
    def __new__(cls, *args, **kwds):
        it = cls.__dict__.get("__it__")
        if it is not None:
            return it
        cls.__it__ = it = object.__new__(cls)
        it.init(*args, **kwds)
        return it
    def init(self, *args, **kwds):
        pass



class SimSingleton(Singleton):
    """
    A singleton class, the instance of which allows access to
    the current simulator.
    """
    actual_sim = None

    # CEBHACKALERT: should both these completely hide that this is
    # SimSingleton, as they do at the moment?
    def __repr__(self):
        """
        Return the simulator's __repr__().
        """
        return self.actual_sim.__repr__()

    def __str__(self):
        """
        Return the simulator's __str__().
        """
        return self.actual_sum.__str__()
    
    def init(self):
        """
        Create a new simulator.
        """
        # Simulator will call this object's change_sim()
        Simulator()

    def __getattribute__(self,attribute):
        """
        If the SimSingleton object has the attribute, return it; if the
        actual_sim has the attribute, return it; otherwise, an AttributeError
        relating to Simulator will be raised (as usual).
        """
        try:
            return object.__getattribute__(self,attribute)
        except AttributeError:
            actual_sim = object.__getattribute__(self,'actual_sim')
            return getattr(actual_sim,attribute)

    def __setattr__(self,name,value):
        """
        If this object has the attribute name, set it to value.
        Otherwise, set self.actual_sim.name=value.

        Unless an attribute is inserted into this object's __dict__,
        the only one it is are 'actual_sim'.
        So, this method really sets attributes on the actual_sim.
        """
        if hasattr(self,name):
            object.__setattr__(self, name, value)
        else:
            object.__setattr__(self.actual_sim, name, value)

    # CEBHACKALERT: no longer need a method
    def change_sim(self,new_sim):
        """
        Set actual_sim to be new_sim.
        """
        assert isinstance(new_sim,Simulator), "Can only change to a Simulator instance."
        self.actual_sim=new_sim<commit_msg>Removed a HACKALERT from SimSingleton.<commit_after>"""
The topographica simulator module.  

The Simulator object is the central object of a Topographica
simulation.  It handles the simulation clock and maintains
communication between the components of the simulation.

A simulation is structured as a directed graph of event-processing nodes
called EventProcessors (EPs).  EventProcessors generate data-carrying
events, which are routed through the graph to other EventProcessors
via delayed connections.

The simulator is modular: EventProcessors should inherit from the root
EventProcessor class.  This class manages the EP's connections to
other EPs, as well as the mechanics of sending events to other EPs
(through the simulator).  The EventProcessor class defines the basic
EP programming interface.

Formally, a simulation event is a tuple:
(time,src,src_port,dest,dest_port,data), where

  time      = The time at which the event should be delivered, an arbitrary
              floating point value.
  src       = The EventProcessor from which the event originated.
  src_port  = The output port from which the event originated
              in the source EP. (see PORTS, below)
  dest      = Destination EventProcessor of the event
  dest_port = The input port to which the event is destined in dest.
              (see PORTS) below.
  data      = The event data to be delivered.  Can be anything.


A simulation begins by giving each EventProcessor an opportunity to
send any initial events.  It then proceeds by processing and
delivering events to EventProcessors in time order.  After all events
for the current time are processed, the simulator gives each
EventProcessor a chance to do any final computation, after which
simulation time skips to the time of the earliest event remaining in
the queue.

PORTS

All connections between EPs are tagged with a source port and a
destination port.  Ports are internal addresses that EPs can use to
distinguish between inputs and outputs.  A port specifier can be any
hashable Python object.  If not specified, the input and output ports
for a connection default to None.

Output ports distinguish different types of output that an EP may
produce. When sending output, the EP must call self.send_output()
separately for each port.  Input ports distinguish different types of
input an EP may receive and process.  The EP is free to interpret the
input port designation on an incoming event in any way it chooses.

An example of input port use might be an EP that receives 'ordinary'
neural activity on the default port, and receives a separate
modulatory signal that influences learning.  The originator of the
modulatory signal might have a connection to the EP with dest_port =
'modulation'.

An example of output port use might be an EP that sends different
events to itself than it sends out to other EPs.  In this case the
self connections might have src_port = 'recurrent'.


Current Simulator

The current Simulator, which can be accessed through the instance
of the Singleton class SimSingleton(), is the last Simulator to
have been created with register=True (the default).


$Id$
"""
__version__='$Revision$'

from parameterizedobject import ParameterizedObject, Parameter
from parameterclasses import Number, BooleanParameter, CallableParameter
from copy import copy, deepcopy
from fixedpoint import FixedPoint

SLEEP_EXCEPTION = "Sleep Exception"
STOP = "Simulator Stopped"

Forever = FixedPoint(-1)


# CEBHACKALERT: this is to be removed; calls
# can be replaced by 'topo.sim'

def get_active_sim():
    """
    Return the active simulator.
    """
    return SimSingleton()


class Singleton(object):
    """
    The singleton pattern.

    To create a singleton class, you subclass from Singleton; each
    subclass will have a single instance, no matter how many times its
    constructor is called. To further initialize the subclass
    instance, subclasses should override 'init' instead of __init__ -
    the __init__ method is called each time the constructor is called.

    From http://www.python.org/2.2.3/descrintro.html#__new__
    """
    def __new__(cls, *args, **kwds):
        it = cls.__dict__.get("__it__")
        if it is not None:
            return it
        cls.__it__ = it = object.__new__(cls)
        it.init(*args, **kwds)
        return it
    def init(self, *args, **kwds):
        pass



class SimSingleton(Singleton):
    """
    A singleton class, the instance of which allows access to
    the current simulator.
    """
    actual_sim = None

    # CEBHACKALERT: should both these completely hide that this is
    # SimSingleton, as they do at the moment?
    def __repr__(self):
        """
        Return the simulator's __repr__().
        """
        return self.actual_sim.__repr__()

    def __str__(self):
        """
        Return the simulator's __str__().
        """
        return self.actual_sum.__str__()
    
    def init(self):
        """
        Create a new simulator.
        """
        # Simulator will call this object's change_sim()
        Simulator()

    def __getattribute__(self,attribute):
        """
        If the SimSingleton object has the attribute, return it; if the
        actual_sim has the attribute, return it; otherwise, an AttributeError
        relating to Simulator will be raised (as usual).
        """
        try:
            return object.__getattribute__(self,attribute)
        except AttributeError:
            actual_sim = object.__getattribute__(self,'actual_sim')
            return getattr(actual_sim,attribute)

    def __setattr__(self,name,value):
        """
        If this object has the attribute name, set it to value.
        Otherwise, set self.actual_sim.name=value.

        Unless an attribute is inserted into this object's __dict__,
        the only one it is are 'actual_sim'.
        So, this method really sets attributes on the actual_sim.
        """
        if hasattr(self,name):
            object.__setattr__(self, name, value)
        else:
            object.__setattr__(self.actual_sim, name, value)

    def change_sim(self,new_sim):
        """
        Set actual_sim to be new_sim.
        """
        assert isinstance(new_sim,Simulator), "Can only change to a Simulator instance."
        self.actual_sim=new_sim
{'fraction_non_alphanumeric': 0.0578368541815017, 'fraction_numerical': 0.0006329614684706068, 'mean_word_length': 3.148342632097145, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, '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': '6019016', 'n_tokens_mistral': 3300, 'n_tokens_neox': 3188, 'n_words': 1529}