Esempio n. 1
0
    def test_assert_no_duplicates(self):
        # Signature: name(lst, error_func=None)
                # Check for duplicates in a sequence.
                #
                # This function checks that a list contains no duplicates, by casting the list
                # to a set and comparing the lengths.
                #
                # It raises an `NineMLRuntimeError` if the lengths are not equal.


        # Duplication
        self.assertRaises(
            NineMLRuntimeError,
            assert_no_duplicates, [1, 2, 3, 4, 4],
        )

        self.assertRaises(
            NineMLRuntimeError,
            assert_no_duplicates, ['1', '2', '3', '4', '4'],
        )

        assert_no_duplicates([1, 2, 3, 4])
        assert_no_duplicates(['1', '2', '3', '4'])

        assert_no_duplicates([None])
        assert_no_duplicates([True])
        assert_no_duplicates([()])
Esempio n. 2
0
    def test_assert_no_duplicates(self):
        # Signature: name(lst, error_func=None)
        # Check for duplicates in a sequence.
        #
        # This function checks that a list contains no duplicates, by casting the list
        # to a set and comparing the lengths.
        #
        # It raises an `NineMLUsageError` if the lengths are not equal.

        # Duplication
        self.assertRaises(
            NineMLUsageError,
            assert_no_duplicates,
            [1, 2, 3, 4, 4],
        )

        self.assertRaises(
            NineMLUsageError,
            assert_no_duplicates,
            ['1', '2', '3', '4', '4'],
        )

        assert_no_duplicates([1, 2, 3, 4])
        assert_no_duplicates(['1', '2', '3', '4'])

        assert_no_duplicates([None])
        assert_no_duplicates([True])
        assert_no_duplicates([()])
Esempio n. 3
0
    def __init__(self, *args, **kwargs):
        BaseALObject.__init__(self)
        ContainerObject.__init__(self)
        valid_kwargs = ('name', 'transitions', 'on_events', 'on_conditions',
                        'time_derivatives', 'aliases')
        for arg in kwargs:
            if arg not in valid_kwargs:
                err = 'Unexpected Arg: %s' % arg
                raise NineMLUsageError(err)

        name = kwargs.get('name', None)
        if name is None:
            self._name = 'default'
        else:
            self._name = validate_identifier(name)
            validate_identifier(self._name)

        # Get Time derivatives from args or kwargs
        kw_tds = normalise_parameter_as_list(
            kwargs.get('time_derivatives', None))
        time_derivatives = list(args) + kw_tds
        # 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 = [TimeDerivative.from_str(o)
                       for o in td_type_dict[basestring]]
        time_derivatives = td_type_dict[TimeDerivative] + td_from_str
        # Check for double definitions:
        td_dep_vars = [td.variable for td in time_derivatives]
        assert_no_duplicates(
            td_dep_vars,
            ("Multiple time derivatives found for the same state variable "
                 "in regime '{}' (found '{}')".format(
                     self.name,
                     "', '".join(td.variable for td in time_derivatives))))
        self.add(*time_derivatives)

        # We support passing in 'transitions', which is a list of both OnEvents
        # and OnConditions as well as separate on_conditions and on_events.
        transitions = normalise_parameter_as_list(
            kwargs.get('transitions', None))
        self.add(*transitions)
        on_conditions = normalise_parameter_as_list(
            kwargs.get('on_conditions', None))
        self.add(*on_conditions)
        on_events = normalise_parameter_as_list(
            kwargs.get('on_events', None))
        self.add(*on_events)

        # Add regime specific aliases
        aliases = normalise_parameter_as_list(kwargs.get('aliases', None))
        self.add(*aliases)
Esempio n. 4
0
    def _resolve_transition_regime_names(self):
        # Check that the names of the regimes are unique:
        names = [r.name for r in self.regimes]
        assert_no_duplicates(names)

        # Create a map of regime names to regimes:
        regime_map = dict([(r.name, r) for r in self.regimes])

        # We only worry about 'target' regimes, since source regimes are taken
        # care of for us by the Regime objects they are attached to.
        for trans in self.transitions:
            if trans.target_regime_name not in regime_map:
                raise NineMLRuntimeError(
                    "Can't find regime '{}'".format(trans.target_regime_name))
            trans.set_target_regime(regime_map[trans.target_regime_name])
Esempio n. 5
0
    def _resolve_transition_regime_names(self):
        # Check that the names of the regimes are unique:
        names = [r.name for r in self.regimes]
        assert_no_duplicates(names)

        # Create a map of regime names to regimes:
        regime_map = dict([(r.name, r) for r in self.regimes])

        # We only worry about 'target' regimes, since source regimes are taken
        # care of for us by the Regime objects they are attached to.
        for trans in self.transitions:
            if trans.target_regime_name not in regime_map:
                raise NineMLRuntimeError("Can't find regime '{}'".format(
                    trans.target_regime_name))
            trans.set_target_regime(regime_map[trans.target_regime_name])
Esempio n. 6
0
 def _resolve_transition_regimes(self):
     # Check that the names of the regimes are unique:
     assert_no_duplicates([r.name for r in self.regimes])
     # We only worry about 'target' regimes, since source regimes are taken
     # care of for us by the Regime objects they are attached to.
     for regime in self.regimes:
         for trans in regime.transitions:
             trans.set_source_regime(regime)
             target = trans.target_regime_name
             if target is None:
                 target = regime  # to same regime
             else:
                 try:
                     target = self.regime(target)  # Lookup by name
                 except KeyError:
                     self.regime(target)
                     raise NineMLUsageError(
                         "Can't find regime '{}' referenced from '{}' "
                         "transition".format(trans.target_regime,
                                             trans.key))
             trans.set_target_regime(target)
Esempio n. 7
0
 def _resolve_transition_regimes(self):
     # Check that the names of the regimes are unique:
     assert_no_duplicates([r.name for r in self.regimes])
     # We only worry about 'target' regimes, since source regimes are taken
     # care of for us by the Regime objects they are attached to.
     for regime in self.regimes:
         for trans in regime.transitions:
             trans.set_source_regime(regime)
             target = trans.target_regime_name
             if target is None:
                 target = regime  # to same regime
             else:
                 try:
                     target = self.regime(target)  # Lookup by name
                 except KeyError:
                     self.regime(target)
                     raise NineMLUsageError(
                         "Can't find regime '{}' referenced from '{}' "
                         "transition".format(trans.target_regime,
                                             trans.key))
             trans.set_target_regime(target)
Esempio n. 8
0
    def __init__(self, regimes=None, aliases=None, state_variables=None):
        """DynamicsBlock 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 = normalise_parameter_as_list(aliases)
        regimes = normalise_parameter_as_list(regimes)
        state_variables = normalise_parameter_as_list(state_variables)

        # Load the aliases as objects or strings:
        alias_td = filter_discrete_types(aliases, (basestring, Alias))
        aliases_from_strs = [Alias.from_str(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, dimension=None) for o in sv_td[basestring]
        ]
        state_variables = sv_td[StateVariable] + sv_from_strings

        assert_no_duplicates(r.name for r in regimes)
        assert_no_duplicates(a.lhs for a in aliases)
        assert_no_duplicates(s.name for s in state_variables)

        self._regimes = dict((r.name, r) for r in regimes)
        self._aliases = dict((a.lhs, a) for a in aliases)
        self._state_variables = dict((s.name, s) for s in state_variables)
Esempio n. 9
0
    def __init__(self, regimes=None, aliases=None, state_variables=None):
        """DynamicsBlock 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 = normalise_parameter_as_list(aliases)
        regimes = normalise_parameter_as_list(regimes)
        state_variables = normalise_parameter_as_list(state_variables)

        # Load the aliases as objects or strings:
        alias_td = filter_discrete_types(aliases, (basestring, Alias))
        aliases_from_strs = [Alias.from_str(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, dimension=None)
                           for o in sv_td[basestring]]
        state_variables = sv_td[StateVariable] + sv_from_strings

        assert_no_duplicates(r.name for r in regimes)
        assert_no_duplicates(a.lhs for a in aliases)
        assert_no_duplicates(s.name for s in state_variables)

        self._regimes = dict((r.name, r) for r in regimes)
        self._aliases = dict((a.lhs, a) for a in aliases)
        self._state_variables = dict((s.name, s) for s in state_variables)
Esempio n. 10
0
    def __init__(self, name, parameters=None, analog_ports=[],
                 event_ports=[],
                 dynamicsblock=None, subnodes=None,
                 portconnections=None, regimes=None,
                 aliases=None, state_variables=None):
        """Constructs a DynamicsClass

        :param name: The name of the componentclass.
        :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 dynamicsblock: A |DynamicsBlock| object, defining the local
                              dynamicsblock of the componentclass.
        :param subnodes: A dictionary mapping namespace-names to sub-
            componentclass. [Type: ``{string:|DynamicsClass|,
            string:|DynamicsClass|, string:|DynamicsClass|}`` ] describing the
            namespace of subcomponents for this componentclass.
        :param portconnections: A list of pairs, specifying the connections
            between the ports of the subcomponents in this componentclass.
            These can be `(|NamespaceAddress|, |NamespaceAddress|)' or
            ``(string, string)``.
        :param interface: A shorthand way of specifying the **interface** for
            this componentclass; |Parameters|, |AnalogPorts| and |EventPorts|.
            ``interface`` takes a list of these objects, and automatically
            resolves them by type into the correct types.

        Examples:

        >>> a = DynamicsClass(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 dynamicsblock is not None:
            if regimes or aliases or state_variables:
                err = "Either specify a 'dynamicsblock' parameter, or "
                err += "state_variables /regimes/aliases, but not both!"
                raise NineMLRuntimeError(err)
        else:
            dynamicsblock = DynamicsBlock(regimes=regimes, aliases=aliases,
                                          state_variables=state_variables)
        ComponentClass.__init__(self, name, parameters,
                                main_block=dynamicsblock)
        self._query = DynamicsQueryer(self)

        # Ensure analog_ports is a list not an iterator
        analog_ports = list(analog_ports)
        event_ports = list(event_ports)

        # Check there aren't any duplicates in the port and parameter names
        assert_no_duplicates(p if isinstance(p, basestring) else p.name
                             for p in chain(parameters if parameters else [],
                                            analog_ports, event_ports))

        self._analog_send_ports = dict(
            (p.name, p) for p in analog_ports if isinstance(p, AnalogSendPort))
        self._analog_receive_ports = dict(
            (p.name, p) for p in analog_ports if isinstance(p,
                                                            AnalogReceivePort))
        self._analog_reduce_ports = dict(
            (p.name, p) for p in analog_ports if isinstance(p,
                                                            AnalogReducePort))

        # Create dummy event ports to keep the ActionVisitor base class of
        # the interface inferrer happy
        self._event_receive_ports = self._event_send_ports = self.subnodes = {}

        # EventPort, StateVariable and Parameter Inference:
        inferred_struct = DynamicsClassInterfaceInferer(self)

        # Check any supplied parameters match:
        if parameters is not None:
            inf_check(self._parameters.keys(),
                      inferred_struct.parameter_names,
                      'Parameters')
        else:
            self._parameters = dict((n, Parameter(n))
                                    for n in inferred_struct.parameter_names)

        # Check any supplied state_variables match:
        if self.dynamicsblock._state_variables:
            state_var_names = [p.name
                               for p in self.dynamicsblock.state_variables]
            inf_check(state_var_names,
                      inferred_struct.state_variable_names,
                      'StateVariables')
        else:
            state_vars = dict((n, StateVariable(n)) for n in
                              inferred_struct.state_variable_names)
            self.dynamicsblock._state_variables = state_vars

        # Set and check event receive ports match inferred
        self._event_receive_ports = dict(
            (p.name, p) for p in event_ports if isinstance(p,
                                                           EventReceivePort))
        if len(self._event_receive_ports):
            # FIXME: not all OutputEvents are necessarily exposed as Ports,
            # so really we should just check that all declared output event
            # ports are in the list of inferred ports, not that the declared
            # list is identical to the inferred one.
            inf_check(self._event_receive_ports.keys(),
                      inferred_struct.input_event_port_names,
                      'Event Ports In')
        else:
            # FIXME: TGC don't like this shorthand
            # Event ports not supplied, so lets use the inferred ones.
            for pname in inferred_struct.input_event_port_names:
                self._event_receive_ports[pname] = EventReceivePort(name=pname)

        # Set and check event send ports match inferred
        self._event_send_ports = dict(
            (p.name, p) for p in event_ports if isinstance(p, EventSendPort))
        if len(self._event_send_ports):
            inf_check(self._event_send_ports.keys(),
                      inferred_struct.event_out_port_names,
                      'Event Ports Out')
        else:
            # Event ports not supplied, so lets use the inferred ones.
            for pname in inferred_struct.event_out_port_names:
                self._event_send_ports[pname] = EventSendPort(name=pname)

        # Call namespace mixin constructor
        _NamespaceMixin.__init__(
            self, subnodes=subnodes, portconnections=portconnections)

        # Finalise initiation:
        self._resolve_transition_regime_names()

        # Store flattening Information:
        self._flattener = None

        # Is the finished componentclass valid?:
        self._validate_self()
Esempio n. 11
0
    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 arg not 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

        self._name = name
        if self.name is not None:
            self._name = self._name.strip()
            ensure_valid_identifier(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 = [TimeDerivative.from_str(o)
                       for o in td_type_dict[basestring]]
        time_derivatives = td_type_dict[TimeDerivative] + td_from_str

        # Check for double definitions:
        td_dep_vars = [td.dependent_variable for td in time_derivatives]
        assert_no_duplicates(td_dep_vars)

        # Store as a dictionary
        self._time_derivatives = dict((td.dependent_variable, td)
                                      for td in time_derivatives)

        # 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)

        # Sort for equality checking
        self._on_events = sorted(self._on_events,
                                 key=lambda x: x.src_port_name)
        self._on_conditions = sorted(self._on_conditions,
                                     key=lambda x: x.trigger)
Esempio n. 12
0
 def action_componentclass(self, componentclass,
                           namespace):  # @UnusedVariable @IgnorePep8
     regime_names = [r.name for r in componentclass.regimes]
     assert_no_duplicates(regime_names)
Esempio n. 13
0
 def action_componentclass(self, componentclass, namespace):  # @UnusedVariable @IgnorePep8
     regime_names = [r.name for r in componentclass.regimes]
     assert_no_duplicates(regime_names)
Esempio n. 14
0
 def action_regime(self, regime, namespace, **kwargs):  # @UnusedVariable
     event_triggers = [on_event.src_port_name
                       for on_event in regime.on_events]
     assert_no_duplicates(event_triggers)
Esempio n. 15
0
    def __init__(self,
                 name,
                 parameters=None,
                 analog_ports=[],
                 event_ports=[],
                 dynamicsblock=None,
                 subnodes=None,
                 portconnections=None,
                 regimes=None,
                 aliases=None,
                 state_variables=None):
        """Constructs a DynamicsClass

        :param name: The name of the componentclass.
        :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 dynamicsblock: A |DynamicsBlock| object, defining the local
                              dynamicsblock of the componentclass.
        :param subnodes: A dictionary mapping namespace-names to sub-
            componentclass. [Type: ``{string:|DynamicsClass|,
            string:|DynamicsClass|, string:|DynamicsClass|}`` ] describing the
            namespace of subcomponents for this componentclass.
        :param portconnections: A list of pairs, specifying the connections
            between the ports of the subcomponents in this componentclass.
            These can be `(|NamespaceAddress|, |NamespaceAddress|)' or
            ``(string, string)``.
        :param interface: A shorthand way of specifying the **interface** for
            this componentclass; |Parameters|, |AnalogPorts| and |EventPorts|.
            ``interface`` takes a list of these objects, and automatically
            resolves them by type into the correct types.

        Examples:

        >>> a = DynamicsClass(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 dynamicsblock is not None:
            if regimes or aliases or state_variables:
                err = "Either specify a 'dynamicsblock' parameter, or "
                err += "state_variables /regimes/aliases, but not both!"
                raise NineMLRuntimeError(err)
        else:
            dynamicsblock = DynamicsBlock(regimes=regimes,
                                          aliases=aliases,
                                          state_variables=state_variables)
        ComponentClass.__init__(self,
                                name,
                                parameters,
                                main_block=dynamicsblock)
        self._query = DynamicsQueryer(self)

        # Ensure analog_ports is a list not an iterator
        analog_ports = list(analog_ports)
        event_ports = list(event_ports)

        # Check there aren't any duplicates in the port and parameter names
        assert_no_duplicates(p if isinstance(p, basestring) else p.name
                             for p in chain(parameters if parameters else [],
                                            analog_ports, event_ports))

        self._analog_send_ports = dict(
            (p.name, p) for p in analog_ports if isinstance(p, AnalogSendPort))
        self._analog_receive_ports = dict((p.name, p) for p in analog_ports
                                          if isinstance(p, AnalogReceivePort))
        self._analog_reduce_ports = dict((p.name, p) for p in analog_ports
                                         if isinstance(p, AnalogReducePort))

        # Create dummy event ports to keep the ActionVisitor base class of
        # the interface inferrer happy
        self._event_receive_ports = self._event_send_ports = self.subnodes = {}

        # EventPort, StateVariable and Parameter Inference:
        inferred_struct = DynamicsClassInterfaceInferer(self)

        # Check any supplied parameters match:
        if parameters is not None:
            inf_check(self._parameters.keys(), inferred_struct.parameter_names,
                      'Parameters')
        else:
            self._parameters = dict(
                (n, Parameter(n)) for n in inferred_struct.parameter_names)

        # Check any supplied state_variables match:
        if self.dynamicsblock._state_variables:
            state_var_names = [
                p.name for p in self.dynamicsblock.state_variables
            ]
            inf_check(state_var_names, inferred_struct.state_variable_names,
                      'StateVariables')
        else:
            state_vars = dict((n, StateVariable(n))
                              for n in inferred_struct.state_variable_names)
            self.dynamicsblock._state_variables = state_vars

        # Set and check event receive ports match inferred
        self._event_receive_ports = dict((p.name, p) for p in event_ports
                                         if isinstance(p, EventReceivePort))
        if len(self._event_receive_ports):
            # FIXME: not all OutputEvents are necessarily exposed as Ports,
            # so really we should just check that all declared output event
            # ports are in the list of inferred ports, not that the declared
            # list is identical to the inferred one.
            inf_check(self._event_receive_ports.keys(),
                      inferred_struct.input_event_port_names, 'Event Ports In')
        else:
            # FIXME: TGC don't like this shorthand
            # Event ports not supplied, so lets use the inferred ones.
            for pname in inferred_struct.input_event_port_names:
                self._event_receive_ports[pname] = EventReceivePort(name=pname)

        # Set and check event send ports match inferred
        self._event_send_ports = dict(
            (p.name, p) for p in event_ports if isinstance(p, EventSendPort))
        if len(self._event_send_ports):
            inf_check(self._event_send_ports.keys(),
                      inferred_struct.event_out_port_names, 'Event Ports Out')
        else:
            # Event ports not supplied, so lets use the inferred ones.
            for pname in inferred_struct.event_out_port_names:
                self._event_send_ports[pname] = EventSendPort(name=pname)

        # Call namespace mixin constructor
        _NamespaceMixin.__init__(self,
                                 subnodes=subnodes,
                                 portconnections=portconnections)

        # Finalise initiation:
        self._resolve_transition_regime_names()

        # Store flattening Information:
        self._flattener = None

        # Is the finished componentclass valid?:
        self._validate_self()
Esempio n. 16
0
 def action_regime(self, regime, namespace, **kwargs):  # @UnusedVariable
     event_triggers = [
         on_event.src_port_name for on_event in regime.on_events
     ]
     assert_no_duplicates(event_triggers)
Esempio n. 17
0
 def __init__(self, componentclass):
     PerNamespaceComponentValidator.__init__(
         self, require_explicit_overrides=True)
     self.all_objects = list()
     self.visit(componentclass)
     assert_no_duplicates(self.all_objects)