def test_flatten_first_level(self): # Signature: name(nested_list) # Flattens the first level of an iterable, ie # # >>> flatten_first_level( [ ['This','is'],['a','short'],['phrase'] ] ) #doctest: +NORMALIZE_WHITESPACE # ['This', 'is', 'a', 'short', 'phrase'] self.assertEqual( flatten_first_level([[1, 2], [3, 4, 5], [6]]), [1, 2, 3, 4, 5, 6] ) self.assertEqual( flatten_first_level(((1, 2), (3, 4, 5), (6,))), [1, 2, 3, 4, 5, 6] ) # Check nesting is not flattened: self.assertEqual( flatten_first_level([[1, ['a', 'b'], 2], [3, 4, ['c', 'd'], 5], [6]]), [1, ['a', 'b'], 2, 3, 4, ['c', 'd'], 5, 6] ) self.assertRaises(NineMLRuntimeError, flatten_first_level, [None]) self.assertRaises(NineMLRuntimeError, flatten_first_level, ['abbn']) self.assertRaises(NineMLRuntimeError, flatten_first_level, [True]) self.assertRaises(NineMLRuntimeError, flatten_first_level, [None, None])
def __init__(self, componentclass, componentname=None): assert isinstance(componentclass, DynamicsClass) # Is our componentclass already flat?? if componentclass.is_flat(): self.reducedcomponent = DynamicsClonerVisitor().visit(componentclass) if componentclass.was_flattened(): self.reducedcomponent.set_flattener(componentclass.flattener) return # New components name self.componentname = componentname if componentname else componentclass.name # Make a clone of the componentclass; in which all hierachical components # have their internal symbols prefixed: cloned_comp = DynamicsClonerVisitorPrefixNamespace().visit(componentclass) # Make a list of all components, and those components with regimes: self.all_components = list(cloned_comp.query.recurse_all_components) self.componentswithregimes = [ m for m in self.all_components if list(m.regimes)] # This will get filled in build_new_regime_space(): (It maps { # (Regime,Regime,...,Regime) : Regime, (Regime,Regime,...,Regime) : # Regime,} Where the key tuple represents the regimes in the # hierachical componentclass, corresponding to self.componentswithregimes. # And the values are the regimes in the new componentclass. self.old_regime_tuple_to_new_regime_map = None # OK, Heavy-lifting Code: # ===================== # self.build_new_regime_space() # Build Our New Component self.reducedcomponent = DynamicsClass( name=self.componentname, aliases=flatten_first_level( [m.aliases for m in self.all_components]), state_variables=flatten_first_level( [m.state_variables for m in self.all_components]), regimes=self.old_regime_tuple_to_new_regime_map.values(), analog_ports=flatten_first_level( [comp.analog_ports for comp in self.all_components]), event_ports=flatten_first_level( [comp.event_ports for comp in self.all_components]), parameters=flatten_first_level([m.parameters for m in self.all_components])) self.remap_analog_ports() # Attach this flattening information to the componentclass: self.reducedcomponent.set_flattener(self)
def remap_analog_ports(self): new_analog_ports = flatten_first_level( [comp.analog_ports for comp in self.all_components]) new_analog_ports = dict([(p.name, p) for p in new_analog_ports]) # Handle port mappings: # portconnections = [ (NS -> NS), (NS -> NS ), (NS -> NS) ] portconnections = [ model.portconnections for model in self.all_components] portconnections = list(itertools.chain(* portconnections)) # ONLY ANALOG PORTS portconnections = [pc for pc in portconnections if pc[ 0].get_local_name() in new_analog_ports] # A. Handle Receive Ports: for src_addr, dst_addr in portconnections[:]: srcport = new_analog_ports[src_addr.get_local_name()] dstport = new_analog_ports[dst_addr.get_local_name()] if dstport.mode == 'recv': DynamicsExpandPortDefinition( originalname=dstport.name, targetname=srcport.name).visit( self.reducedcomponent) del new_analog_ports[dst_addr.get_local_name()] del self.reducedcomponent._analog_receive_ports[ dst_addr.get_local_name()] # expect_single( # [p for p in self.reducedcomponent.analog_receive_ports # if p.name == ])) portconnections.remove((src_addr, dst_addr)) # B. Handle Reduce Ports: # 1/ Make a map { reduce_port -> [send_port1, send_port2, send_port3], # ...} reduce_connections = defaultdict(list) for src, dst in portconnections: dstport = new_analog_ports[dst.get_local_name()] srcport = new_analog_ports[src.get_local_name()] if dstport.mode == 'reduce': reduce_connections[dstport].append(srcport) # 2/ Substitute each reduce port in turn: for dstport, srcport_list in reduce_connections.iteritems(): src_subs = [s.name for s in srcport_list] terms = [dstport.name] + src_subs reduce_expr = dstport.reduce_op.join(terms) # globalRemapPort( dstport.name, reduce_expr ) DynamicsExpandPortDefinition( originalname=dstport.name, targetname=reduce_expr).visit( self.reducedcomponent)
def create_compound_regime(cls, regimetuple, name): # Copy accross all the odes from each regime. # We don't worry about transitions yet, we deal with them later. # We need to clone the time_derivatives: time_derivs = flatten_first_level( [r.time_derivatives for r in regimetuple]) time_derivs = [DynamicsClonerVisitor().visit(td) for td in time_derivs] return Regime(name=name, time_derivatives=time_derivs)
def test_flatten_first_level(self): # Signature: name(nested_list) # Flattens the first level of an iterable, ie # # >>> flatten_first_level( [ ['This','is'],['a','short'],['phrase'] ] ) #doctest: +NORMALIZE_WHITESPACE # ['This', 'is', 'a', 'short', 'phrase'] self.assertEqual(flatten_first_level([[1, 2], [3, 4, 5], [6]]), [1, 2, 3, 4, 5, 6]) self.assertEqual(flatten_first_level(((1, 2), (3, 4, 5), (6, ))), [1, 2, 3, 4, 5, 6]) # Check nesting is not flattened: self.assertEqual( flatten_first_level([[1, ['a', 'b'], 2], [3, 4, ['c', 'd'], 5], [6]]), [1, ['a', 'b'], 2, 3, 4, ['c', 'd'], 5, 6]) self.assertRaises(NineMLRuntimeError, flatten_first_level, [None]) self.assertRaises(NineMLRuntimeError, flatten_first_level, ['abbn']) self.assertRaises(NineMLRuntimeError, flatten_first_level, [True]) self.assertRaises(NineMLRuntimeError, flatten_first_level, [None, None])
def concat(cls, *args): """Concatenates all the Namespace Addresses. This method take all the arguments supplied, converts each one into a namespace object, then, produces a new namespace object which is the concatenation of all the arguments' namespaces. For example: >>> NamespaceAddress.concat('first.second','third.forth','fifth.sixth') NameSpaceAddress: '/first/second/third/forth/fifth/sixth' """ # Turn all the arguments into NamespaceAddress Objects: args = [NamespaceAddress(a) for a in args] # Combine all the location tuples in each argument # into one long list. loc = flatten_first_level([list(a.loctuple) for a in args]) # Create a namespace out of this long new tuple: return NamespaceAddress(loc=tuple(loc))