def check_properties(self): # First check the names properties = set(self.property_names) parameters = set(self.component_class.parameter_names) msg = [] diff_a = properties.difference(parameters) diff_b = parameters.difference(properties) if diff_a: msg.append("User properties of '{}' (url:{}) contain the " "following parameters that are not present in the " "definition of '{}' (url:{}): {}\n\n".format( self.name, self.url, self.component_class.name, self.component_class.url, ",".join(diff_a))) if diff_b: msg.append("Definition of '{}' (url:{}) contains the following " "parameters that are not present in the user properties" " of '{}' (url:{}): {}".format( self.component_class.name, self.component_class.url, self.name, self.url, ",".join(diff_b))) if msg: # need a more specific type of Exception raise NineMLUsageError(". ".join(msg)) # Check dimensions match for param in self.component_class.parameters: prop_units = self.property(param.name).units prop_dimension = prop_units.dimension param_dimension = param.dimension if prop_dimension != param_dimension: raise NineMLUsageError( "Dimensions for '{}' property, {}, in '{}' don't match " "that of its definition in '{}', {}.".format( param.name, prop_dimension, self.name, self.component_class.name, param_dimension))
def nineml_expression(**kwargs): if isinstance(self.rhs, (bool, int, float, BooleanTrue, BooleanFalse)): val = self.rhs else: if self.rhs.is_Boolean: try: val = self.rhs.subs(kwargs) except Exception: raise NineMLUsageError( "Incorrect arguments provided to expression ('{}')" ": '{}'\n".format( "', '".join(self.rhs_symbol_names), "', '".join(list(kwargs.keys())))) else: try: val = self.rhs.evalf(subs=kwargs) except Exception: raise NineMLUsageError( "Incorrect arguments provided to expression '{}'" ": '{}' (expected '{}')\n".format( self.rhs, "', '".join(list(kwargs.keys())), "', '".join(self.rhs_symbol_names))) try: val = float(val) except TypeError: try: locals_dict = deepcopy(kwargs) locals_dict.update(str_to_npfunc_map) val = eval(str(val), {}, locals_dict) except Exception: raise NineMLUsageError( "Could not evaluate expression: {}".format( self.rhs_str)) return val
def __init__(self, target=None, name=None, url=None, document=None): super(BaseReference, self).__init__() if target is not None: assert isinstance(target, DocumentLevelObject) self._target = target if name is not None or url is not None or document is not None: raise NineMLUsageError( "'name', 'url' and 'document' kwargs cannot be used in " "conjunction with 'target'") else: assert name is not None document_url = document.url if document is not None else None if url is not None and url != document_url: if url.startswith('.'): if document_url is None: raise NineMLUsageError( "Must supply a document with a non-None URL that " "is being referenced from if definition is a " "relative URL string, '{}'".format(url)) relative_to = os.path.dirname(document.url) else: relative_to = None if (relative_to is not None and os.path.realpath( os.path.join(relative_to, url)) == document_url): remote_doc = document else: remote_doc = nineml.read(url, relative_to=relative_to) else: remote_doc = document self._target = remote_doc[name]
def __init__(self, lhs, rhs, assign_to_reserved=False): ExpressionWithLHS.__init__(self, rhs) if not is_single_symbol(lhs): err = 'Expecting a single symbol on the LHS; got: %s' % lhs raise NineMLUsageError(err) if not assign_to_reserved and not is_valid_lhs_target(lhs): err = 'Invalid LHS target: %s' % lhs raise NineMLUsageError(err) self._name = validate_identifier(lhs)
def _check_ports(self): if not isinstance(self.send_port, EventSendPort): raise NineMLUsageError( "Send port '{}' must be an EventSendPort to be connected with" " an EventPortConnection".format(self.send_port.name)) if not isinstance(self.receive_port, EventReceivePort): raise NineMLUsageError( "Send port '{}' must be an EventSendPort to be connected with" " an EventPortConnection".format(self.receive_port.name))
def from_tuple(cls, tple, container): # FIXME: Needs comments to explain what is going on and better # exception messages sender, send_port, receiver, receive_port = tple init_kwargs = {} try: sender_dynamicss = getattr(container, sender).component_classes init_kwargs['sender_role'] = sender except AttributeError: try: sender_dynamicss = [container[sender].component_class] init_kwargs['sender_name'] = sender except (TypeError, KeyError) as e: raise NineMLUsageError( "Did not find sender {} '{}' in '{}' container".format( 'name' if isinstance(e, KeyError) else 'role', receiver, container.name)) try: getattr(container, receiver).component_classes init_kwargs['receiver_role'] = receiver except AttributeError: try: container[receiver].component_class init_kwargs['receiver_name'] = receiver except (TypeError, KeyError) as e: raise NineMLUsageError( "Did not find receiver {} '{}' in '{}' container".format( 'name' if isinstance(e, KeyError) else 'role', receiver, container.name)) port_type = None for dyn in sender_dynamicss: pt = dyn.port(send_port).nineml_type if port_type is None: port_type = pt elif port_type != pt: raise NineMLUsageError( "Mismatching port types for '{}' port in populations in " "Selection '{}'".format(send_port, container.name)) if port_type in ('AnalogSendPort', 'AnalogSendPortExposure'): port_connection = AnalogPortConnection( receive_port_name=receive_port, send_port_name=send_port, **init_kwargs) elif port_type in ('EventSendPort', 'EventSendPortExposure'): port_connection = EventPortConnection( receive_port_name=receive_port, send_port_name=send_port, **init_kwargs) else: assert False, "'{}' should be a send port not '{}'".format( send_port, port_type) return port_connection
def add(self, nineml_obj, clone=True, cloner=None, **kwargs): """ Adds a cloned version of the element to the document, setting the document reference (and the corresponding url) of clones to the document. Parameters ---------- nineml_obj : DocumentLevelObject A document level object to add to the document clone : bool Whether to clone the element before adding it to the document clone_definitions : str Whether to clone definitions of user layer objects kwargs : dict Keyword arguments passed to the clone method """ if not isinstance(nineml_obj, DocumentLevelObject): raise NineMLUsageError( "Cannot add {} element to document as it is not a \"document" "-level\" object".format(nineml_obj)) if nineml_obj.name in self: # Ignore if the element is already added (this can happen # implictly when writing other elements that refer to this element) if nineml_obj is not self[nineml_obj.name]: if nineml_obj == self[nineml_obj.name]: nineml_obj = self[nineml_obj.name] else: nineml_obj.find_mismatch(self[nineml_obj.name]) raise NineMLNameError( "Could not add '{}' as a different object with that " "name already exists in the document '{}':\n{}" .format(nineml_obj.name, self.url, nineml_obj.find_mismatch( self[nineml_obj.name]))) elif nineml_obj.document is not None and not clone: raise NineMLUsageError( "Attempting to add the same object '{}' {} to document" " '{}' document when it is already in another " "document, '{}' and 'clone' kwarg is False" .format(nineml_obj.name, nineml_obj.nineml_type, self.url, nineml_obj.document.url)) else: if clone: if cloner is None: cloner = Cloner(**kwargs) nineml_obj = cloner.clone(nineml_obj, **kwargs) AddToDocumentVisitor(self).visit(nineml_obj, **kwargs) return nineml_obj
def __init__(self, rule_properties, source_size, destination_size, **kwargs): # @UnusedVariable if (rule_properties.lib_type == 'OneToOne' and source_size != destination_size): raise NineMLUsageError( "Cannot connect to populations of different sizes " "({} and {}) with OneToOne connection rule" .format(source_size, destination_size)) if not isinstance(rule_properties, ConnectionRuleProperties): raise NineMLUsageError( "'rule_properties' argument ({}) must be a " "ConnectcionRuleProperties instance".format(rule_properties)) self._rule_properties = rule_properties self._source_size = source_size self._destination_size = destination_size
def substitute(self, expr): """ Substitute alias symbols in expression with equivalent expression of inputs, constants and reserved identifiers Parameters ---------- nineml_obj : Expression An expression object to substitute alias symbols in """ if expr.temporary: raise NineMLUsageError( "Attempting to substitute aliases using temporary object " "{}({})".format(type(expr).__name__, expr)) assert isinstance(expr, Expression) try: rhs = self.cache[expr.id] except KeyError: for sym in list(expr.rhs_symbols): # Substitute all alias symbols with their RHS expresssions if str(sym) in self.component_class.alias_names: alias = self.get_alias(str(sym)) expr.subs(sym, self.substitute(alias)) self.cache[expr.id] = rhs = expr.rhs return rhs
def __init__(self, name, definition, properties={}): """ Create a new component_class with the given name, definition and properties, or create a prototype to another component_class that will be resolved later. """ self._name = validate_identifier(name) BaseULObject.__init__(self) DocumentLevelObject.__init__(self) ContainerObject.__init__(self) if isinstance(definition, basestring): if "#" in definition: defn_url, name = definition.split("#") else: raise NineMLUsageError( "Must provide name of class using '#' syntax when " "providing definition as url string ('{}')".format( definition)) definition = Definition(name=name, document=None, url=defn_url) elif (isinstance(definition, ComponentClass) or definition.nineml_type in ('Dynamics', 'MultiDynamics')): definition = Definition(definition) elif (isinstance(definition, Component) or definition.nineml_type in ('DynamicsProperties', 'MultiDynamicsProperties')): definition = Prototype(definition) elif definition.nineml_type not in ('Definition', 'Prototype'): raise ValueError("'definition' must be either a 'Definition', " "'Prototype' element or url pointing to a " "dynamics class") self._definition = definition if isinstance(properties, dict): properties = (Property(name, qty) for name, qty in properties.items()) self.add(*properties) self.check_properties()
def __init__(self, name, source, destination, source_port, destination_port, delay, connectivity=None, connection_rule_properties=None, connectivity_class=Connectivity): self._name = validate_identifier(name) BaseULObject.__init__(self) DocumentLevelObject.__init__(self) self._source = source self._destination = destination self._source_port = source_port self._destination_port = destination_port if connectivity is not None: assert isinstance(connectivity, BaseConnectivity) if connection_rule_properties is not None: raise NineMLUsageError( "Cannot provide both connectivty and " "connection_rule_properties as kwargs to projection class") self._connectivity = connectivity else: connectivity = connectivity_class( connection_rule_properties, source.size, destination.size) self._connectivity = connectivity self._delay = delay if isinstance(source_port, Port): self._check_ports(source_port, destination_port)
def __init__(self, name, dimension=None, operator='+'): if operator not in list(self._operator_map.keys()): err = ("%s('%s')" + "specified undefined operator: '%s'") %\ (self.__class__.__name__, name, str(operator)) raise NineMLUsageError(err) super(AnalogReducePort, self).__init__(name, dimension) self._operator = str(operator)
def __getitem__(self, index): if self.value.is_array(): return self._value.values[index] * self.units elif self.value.is_single(): return self._value.value * self.units else: raise NineMLUsageError("Cannot get item from random distribution")
def from_sympy(self, expr): if expr == 1: return dimensionless elif not isinstance(expr, sympy.Basic): raise NineMLUsageError( "Cannot convert '{}' dimension, must be 1 or sympy expression". format(expr)) powers = {} stack = [expr] while stack: expr = stack.pop() if isinstance(expr, sympy.Mul): stack.extend(expr.args) elif isinstance(expr, sympy.Pow): powers[str(expr.args[0])] = expr.args[1] else: powers[str(expr)] = 1 name_num = [] name_den = [] for sym, p in powers.items(): name = self.dimension_names[next( i for i, s in enumerate(self.dimension_symbols) if s == sym)] if abs(p) > 1: name += str(abs(p)) if p > 0: name_num.append(name) else: name_den.append(name) name = '_'.join(name_num) if name_den: if name: name += '_' name += 'per_' + '_'.join(name_den) return Dimension(name, **powers)
def check_initial_values(self): for var in self.definition.component_class.state_variables: try: initial_value = self.initial_value(var.name) except KeyError: raise NineMLUsageError( "Initial value not specified for {}".format(var.name)) initial_units = initial_value.units initial_dimension = initial_units.dimension var_dimension = var.dimension if initial_dimension != var_dimension: raise NineMLUsageError( "Dimensions for '{}' initial value, {}, in '{}' don't " "match that of its definition in '{}', {}.".format( var.name, initial_dimension, self.name, self.component_class.name, var_dimension))
def from_str(cls, alias_string): """Creates an Alias object from a string""" if not cls.is_alias_str(alias_string): errmsg = "Invalid Alias: %s" % alias_string raise NineMLUsageError(errmsg) lhs, rhs = alias_string.split(':=') return Alias(name=lhs.strip(), rhs=rhs.strip())
def __init__(self, component_class, **kwargs): # @UnusedVariable BaseDynamicsVisitor.__init__(self) self.sv_declared = [] self.time_derivatives_used = [] self.visit(component_class) for td in self.time_derivatives_used: if td not in self.sv_declared: raise NineMLUsageError( "StateVariable '{}' not declared".format(td))
def __pow__(self, power): "self ** expr" if self.offset != 0: raise NineMLUsageError( "Can't raise units to power with nonzero offsets ({})".format( self)) return Unit(Dimension.make_name([self.name], power=power), dimension=(self.dimension**power), power=(self.power * power))
def __init__(self, component_class, **kwargs): # @UnusedVariable BaseDynamicsVisitor.__init__(self) self.sv_declared = [] self.state_assignments_lhs = [] self.visit(component_class) for sa in self.state_assignments_lhs: if sa not in self.sv_declared: raise NineMLUsageError( "Not Assigning to state-variable: {}".format(sa))
def check_conflicting_symbol(self, symbol): symbol = symbol.lower() if symbol in self.symbols: raise NineMLUsageError( "Found duplication of '{}' symbol in {} " "(Note that symbols must be case-insensitively unique despite " "being case-sensitive in general)".format( symbol, self.component_class)) self.symbols.append(symbol)
def __init__(self, name, pre, post, response, delay, connectivity=None, connection_rule_properties=None, plasticity=None, port_connections=None, analog_port_connections=None, event_port_connections=None, connectivity_class=Connectivity, **kwargs): """ Create a new projection. """ self._name = validate_identifier(name) BaseULObject.__init__(self) ContainerObject.__init__(self) DocumentLevelObject.__init__(self) assert isinstance(name, basestring) assert isinstance(delay, Quantity) assert isinstance(pre, (Population, Selection)) assert isinstance(post, (Population, Selection)) assert isinstance(response, DynamicsProperties) assert isinstance(plasticity, (DynamicsProperties, type(None))) self._pre = pre self._post = post self._response = response self._plasticity = plasticity if connectivity is not None: assert isinstance(connectivity, Connectivity) if connection_rule_properties is not None: raise NineMLUsageError( "Cannot provide both connectivty and " "connection_rule_properties as kwargs to projection class") self._connectivity = connectivity else: self._connectivity = connectivity_class(connection_rule_properties, pre.size, post.size, **kwargs) self._delay = delay if port_connections is None: port_connections = [] if analog_port_connections is None: analog_port_connections = [] if event_port_connections is None: event_port_connections = [] for port_connection in chain(port_connections, event_port_connections, analog_port_connections): if isinstance(port_connection, tuple): port_connection = BasePortConnection.from_tuple( port_connection, self) port_connection.bind(self, to_roles=True) self.add(port_connection)
def _check_ports(self): if not isinstance(self.send_port, AnalogSendPort): raise NineMLUsageError( "Send port '{}' must be an AnalogSendPort to be connected with" " an AnalogPortConnection".format(self.send_port.name)) if not isinstance(self.receive_port, (AnalogReceivePort, AnalogReducePort)): raise NineMLUsageError( "Send port '{}' must be an AnalogSendPort to be connected with" " an AnalogPortConnection".format(self.receive_port.name)) if self.send_port.dimension != self.receive_port.dimension: raise NineMLDimensionError( "Dimensions do not match in analog port connection: sender " "port" " '{}' has dimensions of '{}' and receive port '{}' has" " dimensions of '{}'".format(self.send_port.name, self.send_port.dimension, self.receive_port.name, self.receive_port.dimension))
def check_conflicting_dimension(self, dimension): try: if dimension != self.dimensions[dimension.name]: err = ("Duplication of dimension name '{}' for differing " "dimensions ('{}', '{}')".format( dimension.name, dimension, self.dimensions[dimension.name])) raise NineMLUsageError(err) except KeyError: self.dimensions[dimension.name] = dimension
def __init__(self, component_class, **kwargs): # @UnusedVariable super(EventPortsDynamicsValidator, self).__init__() # Mapping component_class to list of events/eventports at that # component_class self.event_send_ports = {} self.event_receive_ports = {} self.output_events = [] self.input_events = [] # Visit all elements of the component class self.visit(component_class) # Check that each output event has a corresponding event_port with a # send mode: for output_event in self.output_events: if output_event not in self.event_send_ports: raise NineMLUsageError( "Can't find port definition matching OutputEvent: {}" .format(output_event)) # Check that each input event has a corresponding event_port with a # recv/reduce mode: for input_event in self.input_events: if input_event not in self.event_receive_ports: raise NineMLUsageError( "Can't find port definition matching input event: {}" .format(input_event)) # Check that each EventSendPort emits at least one output event for port_name in list(self.event_send_ports.keys()): if port_name not in self.output_events: raise NineMLUsageError( "Unable to find events generated for '{}' in '{}'" .format(port_name, component_class.name)) # Check that each Event port emits/recieves at least one for port_name in list(self.event_receive_ports.keys()): if port_name not in self.input_events: raise NineMLUsageError( "Unable to find event transitions triggered by '{}' in " "'{}'".format(port_name, component_class.name))
def __init__(self, items, **kwargs): BaseULObject.__init__(self, **kwargs) ContainerObject.__init__(self, **kwargs) items = list(items) if all(isinstance(it, Item) for it in items): indices = [it.index for it in items] if min(indices) < 0 or max(indices) > len(indices): raise NineMLUsageError( "Indices are not contiguous, have duplicates, or don't " "start from 0 ({})" .format(', '.join(str(i) for i in indices))) self.add(*items) elif any(isinstance(it, Item) for it in items): raise NineMLUsageError( "Cannot mix Items and Populations/Selections in Concatenate " "__init__ method ({})".format(', '.join(str(it) for it in items))) else: self.add(*(Item(i, p) for i, p in enumerate(items))) assert(self.num_items)
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)
def default_action(self, obj, **kwargs): # @UnusedVariable if obj.id in self.ids: raise NineMLUsageError( "ID of {} {} ({}) already seen [{}]".format( type(obj).__name__, obj, obj.id, self.context_str())) if self.print_all: print('{}: {}, {} [{}]'.format(obj.id, type(obj).__name__, obj, self.context_str())) self.ids.append(obj.id) if obj.temporary: self.temp_mem_address.add(id(obj))
def __mul__(self, other): "self * other" try: if (self.offset != 0 or other.offset != 0): raise NineMLUsageError( "Can't multiply units with nonzero offsets ({} and {})". format(self, other)) return Unit(Dimension.make_name([self.name, other.name]), dimension=self.dimension * other.dimension, power=(self.power + other.power)) except AttributeError: return Quantity(other, self)
def get_alias(self, name): alias = None for context in reversed(self.contexts): try: alias = context.parent.alias(name) break except (NineMLNameError, AttributeError): continue if alias is None: raise NineMLUsageError("Did not find alias '{}' in any " "context".format(name)) return alias
def __init__(self, component_class, **kwargs): # @UnusedVariable super(OutputAnalogPortsDynamicsValidator, self).__init__() self.output_analogports = [] self.available_symbols = [] self.component_class = component_class self.visit(component_class) for ap in self.output_analogports: if ap not in self.available_symbols: raise NineMLUsageError( "Unable to find an Alias or State variable for " "analog-port '{}' (available '{}')" .format(ap, "', '".join(self.available_symbols)))