def __init__(self, regimes=None, aliases=None, state_variables=None): """Dynamics object constructor :param aliases: A list of aliases, which must be either |Alias| objects or ``string``s. :param regimes: A list containing at least one |Regime| object. :param state_variables: An optional list of the state variables, which can either be |StateVariable| objects or `string` s. If provided, it must match the inferred state-variables from the regimes; if it is not provided it will be inferred automatically. """ aliases = nineml.utility.normalise_parameter_as_list(aliases) regimes = nineml.utility.normalise_parameter_as_list(regimes) state_variables = nineml.utility.normalise_parameter_as_list(state_variables) # Load the aliases as objects or strings: from nineml.utility import filter_discrete_types alias_td = filter_discrete_types(aliases, (basestring, Alias)) aliases_from_strs = [StrToExpr.alias(o) for o in alias_td[basestring]] aliases = alias_td[Alias] + aliases_from_strs # Load the state variables as objects or strings: sv_types = (basestring, StateVariable) sv_td = filter_discrete_types(state_variables, sv_types) sv_from_strings = [StateVariable(o) for o in sv_td[basestring]] state_variables = sv_td[StateVariable] + sv_from_strings self._regimes = regimes self._aliases = aliases self._state_variables = state_variables
def __init__(self, *args, **kwargs): """Regime constructor :param name: The name of the constructor. If none, then a name will be automatically generated. :param time_derivatives: A list of time derivatives, as either ``string``s (e.g 'dg/dt = g/gtau') or as |TimeDerivative| objects. :param transitions: A list containing either |OnEvent| or |OnCondition| objects, which will automatically be sorted into the appropriate classes automatically. :param *args: Any non-keyword arguments will be treated as time_derivatives. """ valid_kwargs = ('name', 'transitions', 'time_derivatives') for arg in kwargs: if not arg in valid_kwargs: err = 'Unexpected Arg: %s' % arg raise NineMLRuntimeError(err) transitions = kwargs.get('transitions', None) name = kwargs.get('name', None) kw_tds = normalise_parameter_as_list(kwargs.get('time_derivatives', None)) time_derivatives = list(args) + kw_tds # Generate a name for unnamed regions: self._name = name.strip() if name else Regime.get_next_name() ensure_valid_c_variable_name(self._name) # Un-named arguments are time_derivatives: time_derivatives = normalise_parameter_as_list(time_derivatives) # time_derivatives.extend( args ) td_types = (basestring, TimeDerivative) td_type_dict = filter_discrete_types(time_derivatives, td_types) td_from_str = [StrToExpr.time_derivative(o) for o in td_type_dict[basestring]] self._time_derivatives = td_type_dict[TimeDerivative] + td_from_str # Check for double definitions: td_dep_vars = [td.dependent_variable for td in self._time_derivatives] assert_no_duplicates(td_dep_vars) # We support passing in 'transitions', which is a list of both OnEvents # and OnConditions. So, lets filter this by type and add them # appropriately: transitions = normalise_parameter_as_list(transitions) f_dict = filter_discrete_types(transitions, (OnEvent, OnCondition)) self._on_events = [] self._on_conditions = [] # Add all the OnEvents and OnConditions: for event in f_dict[OnEvent]: self.add_on_event(event) for condition in f_dict[OnCondition]: self.add_on_condition(condition)
def test_filter_discrete_types(self): # Signature: name(lst, acceptedtypes) # Creates a dictionary mapping types to objects of that type. # # Starting with a list of object, and a list of types, this returns a # dictionary mapping each type to a list of objects of that type. # # For example:: # # >>> import types # >>> filter_discrete_types( ['hello',1,2,'world'], ( basestring, types.IntType) ) #doctest: +NORMALIZE_WHITESPACE # {<type 'basestring'>: ['hello', 'world'], <type 'int'>: [1, 2]} # # # The function checks that each object is mapped to exactly one type from nineml.utility import filter_discrete_types import numbers import types from nineml.exceptions import NineMLRuntimeError # Good Case: data = ['hello', 'world', 1, 2, 3] types = [basestring, numbers.Number, types.BooleanType] filtered = filter_discrete_types(data, types) self.assertEqual(filtered[basestring], ['hello', 'world']) self.assertEqual(filtered[numbers.Number], [1, 2, 3]) # Not all objects covered by listed classes: self.assertRaises( NineMLRuntimeError, filter_discrete_types, data, [basestring] )
def __init__(self, name, parameters=None): self._name = name # Turn any strings in the parameter list into Parameters: if parameters is None: self._parameters = [] else: param_types = (basestring, Parameter) param_td = filter_discrete_types(parameters, param_types) params_from_strings = [Parameter(s) for s in param_td[basestring]] self._parameters = param_td[Parameter] + params_from_strings
def do_to_assignments_and_events(doList): if not doList: return [], [] # 'doList' is a list of strings, OutputEvents, and StateAssignments. do_type_list = (OutputEvent, basestring, StateAssignment) do_types = filter_discrete_types(doList, do_type_list) # Convert strings to StateAssignments: sa_from_strs = [StrToExpr.state_assignment(s) for s in do_types[basestring]] return do_types[StateAssignment] + sa_from_strs, do_types[OutputEvent]
def __init__(self, state_assignments=None, event_outputs=None, target_regime_name=None): """Abstract class representing a transition from one |Regime| to another. |Transition| objects are not created directly, but via the subclasses |OnEvent| and |OnCondition|. :param state_assignments: A list of the state-assignments performed when this transition occurs. Objects in this list are either `string` (e.g A = A+13) or |StateAssignment| objects. :param event_outputs: A list of |OutputEvent| objects emitted when this transition occurs. :param target_regime_name: The name of the regime to go into after this transition. ``None`` implies staying in the same regime. This has to be specified as a string, not the object, because in general the |Regime| object is not yet constructed. This is automatically resolved by the |ComponentClass| in ``_ResolveTransitionRegimeNames()`` during construction. .. todo:: For more information about what happens at a regime transition, see here: XXXXXXX """ if target_regime_name: assert isinstance(target_regime_name, basestring) # Load state-assignment objects as strings or StateAssignment objects from nineml.utility import filter_discrete_types state_assignments = state_assignments or [] sa_types = (basestring, StateAssignment) sa_type_dict = filter_discrete_types(state_assignments, sa_types) sa_from_str = [StrToExpr.state_assignment(o) for o in sa_type_dict[basestring]] self._state_assignments = sa_type_dict[StateAssignment] + sa_from_str self._event_outputs = event_outputs or [] self._target_regime_name = target_regime_name self._source_regime_name = None # Set later, once attached to a regime: self._target_regime = None self._source_regime = None
def __init__(self, name, parameters=None, analog_ports=None, event_ports=None, dynamics=None, subnodes=None, portconnections=None, regimes=None, aliases=None, state_variables=None): """Constructs a ComponentClass :param name: The name of the component. :param parameters: A list containing either |Parameter| objects or strings representing the parameter names. If ``None``, then the parameters are automatically inferred from the |Dynamics| block. :param analog_ports: A list of |AnalogPorts|, which will be the local |AnalogPorts| for this object. :param event_ports: A list of |EventPorts| objects, which will be the local event-ports for this object. If this is ``None``, then they will be automatically inferred from the dynamics block. :param dynamics: A |Dynamics| object, defining the local dynamics of the component. :param subnodes: A dictionary mapping namespace-names to sub-component. [Type: ``{string:|ComponentClass|, string:|ComponentClass|, string:|ComponentClass|}`` ] describing the namespace of subcomponents for this component. :param portconnections: A list of pairs, specifying the connections between the ports of the subcomponents in this component. These can be `(|NamespaceAddress|, |NamespaceAddress|)' or ``(string, string)``. :param interface: A shorthand way of specifying the **interface** for this component; |Parameters|, |AnalogPorts| and |EventPorts|. ``interface`` takes a list of these objects, and automatically resolves them by type into the correct types. Examples: >>> a = ComponentClass(name='MyComponent1') .. todo:: Point this towards and example of constructing ComponentClasses. This can't be here, because we also need to know about dynamics. For examples """ # We can specify in the componentclass, and they will get forwarded to # the dynamics class. We check that we do not specify half-and-half: if dynamics is not None: if regimes or aliases or state_variables: err = "Either specify a 'dynamics' parameter, or " err += "state_variables /regimes/aliases, but not both!" raise NineMLRuntimeError(err) else: # We should always create a dynamics object, even is it is empty: dynamics = dyn.Dynamics(regimes=regimes, aliases=aliases, state_variables=state_variables) # Turn any strings in the parameter list into Parameters: from nineml.utility import filter_discrete_types if parameters is not None: param_types = (basestring, Parameter) param_td = filter_discrete_types(parameters, param_types) params_from_strings = [Parameter(s) for s in param_td[basestring]] parameters = param_td[Parameter] + params_from_strings self._query = componentqueryer.ComponentQueryer(self) # EventPort, StateVariable and Parameter Inference: inferred_struct = InterfaceInferer(dynamics, analog_ports=analog_ports) inf_check = lambda l1, l2, desc: check_list_contain_same_items(l1, l2, desc1='Declared', desc2='Inferred', ignore=['t'], desc=desc) # Check any supplied parameters match: if parameters is not None: parameter_names = [p.name for p in parameters] inf_check(parameter_names, inferred_struct.parameter_names, 'Parameters') else: parameters = [Parameter(n) for n in inferred_struct.parameter_names] # Check any supplied state_variables match: if dynamics._state_variables: state_var_names = [p.name for p in dynamics.state_variables] inf_check(state_var_names, inferred_struct.state_variable_names, 'StateVariables') else: state_vars = [StateVariable(n) for n in inferred_struct.state_variable_names] dynamics._state_variables = state_vars # Check Event Ports Match: if event_ports is not None: ip_evt_names = [ep.name for ep in event_ports if ep.is_incoming()] op_evt_names = [ep.name for ep in event_ports if ep.is_outgoing()] # Check things Match: inf_check(ip_evt_names, inferred_struct.input_event_port_names, 'Event Ports In') inf_check(op_evt_names, inferred_struct.output_event_port_names, 'Event Ports Out') else: event_ports = [] # Event ports not supplied, so lets use the inferred ones. for evt_port_name in inferred_struct.input_event_port_names: event_ports.append(EventPort(name=evt_port_name, mode='recv')) for evt_port_name in inferred_struct.output_event_port_names: event_ports.append(EventPort(name=evt_port_name, mode='send')) # Construct super-classes: ComponentClassMixinFlatStructure.__init__(self, name=name, parameters=parameters, analog_ports=analog_ports, event_ports=event_ports, dynamics=dynamics) ComponentClassMixinNamespaceStructure.__init__(self, subnodes=subnodes, portconnections=portconnections) # Finalise initiation: self._resolve_transition_regime_names() # Store flattening Information: self._flattener = None # Is the finished component valid?: self._validate_self()