def check_compose(): from mocdp.example_battery.dp_bat import BatteryDP from mocdp.example_battery.dp_bat2 import Mobility actuation = dpwrap(Mobility(), 'weight', 'actuation_power') check_ftype(actuation, 'weight', R_Weight_g) check_rtype(actuation, 'actuation_power', R_Power) battery = dpwrap(BatteryDP(energy_density=100.0), 'capacity', 'weight') check_ftype(battery, 'capacity', R_Energy) check_rtype(battery, 'weight', R_Weight_g) times = dpwrap(Product(R_Time, R_Power, R_Energy), ['mission_time', 'power'], 'energy') check_ftype(times, 'mission_time', R_Time) check_ftype(times, 'power', R_Power) check_rtype(times, 'energy', R_Energy) c = Connection('actuation', 'actuation_power', 'times', 'power') x = dpconnect(dict(actuation=actuation, times=times), [c]) print('WE have obtained x') print('x = %s' % x) print('x fun: %s' % x.get_dp().get_fun_space()) print('x res: %s' % x.get_dp().get_res_space()) # "battery.capacity >= x.energy" c = Connection('x', 'energy', 'battery', 'capacity') _y = dpconnect(dict(battery=battery, x=x), [c])
def make_approximation_f(name, approx_perc, approx_abs, approx_abs_S, max_value, max_value_S, ndp): F = ndp.get_ftype(name) ndp_before = get_approx_dp(F, name, approx_perc, approx_abs, approx_abs_S, max_value, max_value_S) name2ndp = {NAME_ORIGINAL: ndp, NAME_APPROX: ndp_before} fnames = ndp.get_fnames() rnames = ndp.get_rnames() connections = [] connections.append(Connection(NAME_APPROX, name, NAME_ORIGINAL, name)) for fn in fnames: F = ndp.get_ftype(fn) fn_ndp = dpwrap(Identity(F), fn, fn) fn_name = get_name_for_fun_node(fn) name2ndp[fn_name] = fn_ndp if fn == name: connections.append(Connection(fn_name, fn, NAME_APPROX, fn)) else: connections.append(Connection(fn_name, fn, NAME_ORIGINAL, fn)) for rn in rnames: R = ndp.get_rtype(rn) rn_ndp = dpwrap(Identity(R), rn, rn) rn_name = get_name_for_res_node(rn) name2ndp[rn_name] = rn_ndp connections.append(Connection(NAME_ORIGINAL, rn, rn_name, rn)) return CompositeNamedDP.from_parts(name2ndp, connections, fnames, rnames)
def check_compose2_generic(): actuation = dpwrap(Mobility(), 'weight', 'actuation_power') battery = dpwrap((BatteryDP(energy_density=100.0)), 'capacity', 'battery_weight') times = dpwrap((Product(R_Time, R_Power, R_Energy)), ['mission_time', 'power'], 'energy') c1 = Connection('actuation', 'actuation_power', 'times', 'power') c2 = Connection('times', 'energy', 'battery', 'capacity') c3 = Connection('battery', 'battery_weight', 'actuation', 'weight') y = dpgraph(dict(actuation=actuation, times=times, battery=battery), [c1, c2, c3], split=[]) print y.desc() assert y.get_fnames() == ['mission_time'], y.get_fnames() assert y.get_rnames() == [], y.get_rnames() check_ftype(y, 'mission_time', R_Time) dp = y.get_dp() funsp = dp.get_fun_space() ressp = dp.get_res_space() assert funsp == R_Time, funsp assert ressp == PosetProduct(()), ressp
def cndp_remove_one_child(cndp, to_remove): """ Removes a child from NDP. Assumes ndp connected. Dangling arrows are substituted with top/bottom. """ print('removing %r' % to_remove) cndp.check_fully_connected() name2ndp = cndp.get_name2ndp() assert to_remove in name2ndp connections = cndp.get_connections() fnames = cndp.get_fnames() rnames = cndp.get_rnames() name2ndp_i = dict((k, v) for k, v in name2ndp.items() if k != to_remove) filter_c = lambda c: not c.involves_any_of_these_nodes([to_remove]) connections_i = filter(filter_c, connections) ndp2 = CompositeNamedDP.from_parts(name2ndp=name2ndp_i, connections=connections_i, fnames=fnames, rnames=rnames) unconnected_fun, unconnected_res = get_missing_connections(ndp2.context) for r in [CResource(*_) for _ in unconnected_res]: R = ndp2.context.get_rtype(r) values = R.get_maximal_elements() dp = LimitMaximals(R, values) new_ndp = dpwrap(dp, 'limit', []) name = ndp2.context.new_name('_limit_r') ndp2.context.add_ndp(name, new_ndp) c = Connection(dp2=name, s2='limit', dp1=r.dp, s1=r.s) ndp2.context.add_connection(c) for f in [CFunction(*_) for _ in unconnected_fun]: F = ndp2.context.get_ftype(f) values = F.get_minimal_elements() dp = ConstantMinimals(F, values) new_ndp = dpwrap(dp, [], 'limit') name = ndp2.context.new_name('_limit_f') ndp2.context.add_ndp(name, new_ndp) c = Connection(dp1=name, s1='limit', dp2=f.dp, s2=f.s) ndp2.context.add_connection(c) ndp2.check_fully_connected() return ndp2
def cndp_create_one_without_some_connections(ndp, exclude_connections, names): """ Creates a new CompositeNDP without some of the connections. A new function / resource pair is created for each cut connection. """ from mocdp.comp.context import Context context = Context() # Create the fun/res node in the original order for fname in ndp.get_fnames(): # simply copy the functionnode - it might be a LabeledNDP name = get_name_for_fun_node(fname) fndp = ndp.get_name2ndp()[name] context.fnames.append(fname) context.add_ndp(name, fndp) for rname in ndp.get_rnames(): # simply copy the functionnode - it might be a LabeledNDP name = get_name_for_res_node(rname) rndp = ndp.get_name2ndp()[name] context.rnames.append(rname) context.add_ndp(name, rndp) for _name, _ndp in ndp.get_name2ndp().items(): isf, fname = is_fun_node_name(_name) isr, rname = is_res_node_name(_name) if isf and fname in ndp.get_fnames(): pass elif isr and rname in ndp.get_rnames(): pass else: # print('regular: %r' % _name) context.add_ndp(_name, _ndp) for c in ndp.get_connections(): if c in exclude_connections: continue # print('adding connection %s' % str(c)) context.connections.append(c) # print('done') # for each cut connection for e, name in zip(exclude_connections, names): S = context.get_rtype(CResource(e.dp1, e.s1)) fn = context.add_ndp_fun_node(name, S) rn = context.add_ndp_res_node(name, S) c1 = Connection(e.dp1, e.s1, rn, name) c2 = Connection(fn, name, e.dp2, e.s2) context.connections.append(c1) context.connections.append(c2) return CompositeNamedDP.from_context(context)
def wrap_change_name_function(ndp, fn, fn2): from mocdp.comp.wrap import dpwrap F = ndp.get_ftype(fn) tmpname = '__tmp_%s' % fn first = dpwrap(Identity(F), fn2, tmpname) from mocdp.comp.connection import connect2 connections = set([Connection('-', tmpname, '-', fn)]) return connect2(first, ndp, connections, split=[])
def reorder_functions(ndp, rnames): F = ndp.get_ftypes(rnames) ndp0 = dpwrap(Identity(F), rnames, rnames) connections = [Connection('*', fn, '*', fn) for fn in rnames] return connect2(ndp0, res, set(connections), split=[], repeated_ok=True)
def wrap_change_name_resource(ndp, rn, rn2): from mocdp.comp.wrap import dpwrap R = ndp.get_rtype(rn) tmpname = '__tmp_%s' % rn second = dpwrap(Identity(R), tmpname, rn2) from mocdp.comp.connection import connect2 connections = set([Connection('-', rn, '-', tmpname)]) return connect2(ndp, second, connections, split=[])
def reorder_resources(ndp, rnames): R = ndp.get_rtypes(rnames) ndp2 = dpwrap(Identity(R), rnames, rnames) connections = [Connection('*', rn, '*', rn) for rn in rnames] return connect2(res, ndp2, set(connections), split=[], repeated_ok=True)
def ignore_some(ndp, ignore_fnames, ignore_rnames): """ Ignores some functionalities or resources """ fnames0 = ndp.get_fnames() rnames0 = ndp.get_rnames() for fname in ignore_fnames: check_isinstance(fname, str) if not fname in fnames0: msg = 'Could not find functionality %r in %r.' % (fname, fnames0) raise_desc(ValueError, msg, fname=fname, fnames=fnames0) for rname in ignore_rnames: check_isinstance(rname, str) if not rname in rnames0: msg = 'Could not find resource %r in %r.' % (rname, rnames0) raise_desc(ValueError, msg, rname=rname, rnames=rnames0) c = Context() orig = '_orig' c.add_ndp(orig, ndp) for fname in ndp.get_fnames(): F = ndp.get_ftype(fname) if fname in ignore_fnames: dp = Constant(F, F.get_bottom()) n = '_const_f_%s' % fname c.add_ndp(n, dpwrap(dp, [], fname)) else: n = c.add_ndp_fun_node(fname, F) con = Connection(n, fname, orig, fname) c.add_connection(con) for rname in ndp.get_rnames(): R = ndp.get_rtype(rname) if rname in ignore_rnames: dp = LimitMaximals(R, R.get_maximal_elements()) n = '_const_r_%s' % rname c.add_ndp(n, dpwrap(dp, rname, [])) else: n = c.add_ndp_res_node(rname, R) con = Connection(orig, rname, n, rname) c.add_connection(con) return CompositeNamedDP.from_context(c)
def get_lower_bound_ndp(context): """ We create an NDP where each open resource becomes a new resource. and all the functions are given a lower bound of 0. The new resources are given a name like: dummy<i> """ context = clone_context(context) unconnected_fun, unconnected_res = get_missing_connections(context) # let's remove the new resources that are unconnected for rname, name, _ndp in context.iterate_new_resources(): if (name, rname) in unconnected_fun: unconnected_fun.remove((name, rname)) del context.names[name] context.rnames.remove(rname) # create a new resource for each unconnected resource resource2var = {} # CResource -> str for dp, s in unconnected_res: r = CResource(dp, s) R = context.get_rtype(r) rname = 'dummy%d' % len(resource2var) context.add_ndp_res_node(rname, R) c = Connection(dp1=dp, s1=s, dp2=get_name_for_res_node(rname), s2=rname) context.add_connection(c) resource2var[r] = rname # add a minimal bound for all unconnected functions for dp, s in unconnected_fun: f = CFunction(dp, s) F = context.get_ftype(f) minimals = F.get_minimal_elements() res = get_constant_minimals_as_resources(F, minimals, context) c = Connection(dp1=res.dp, s1=res.s, dp2=dp, s2=s) context.add_connection(c) ndp = CompositeNamedDP.from_context(context) ndp.check_fully_connected() return ndp, resource2var
def check_compose2_fail(): """ Fails because there is a recursive constraint """ actuation = dpwrap((Mobility()), 'weight', 'actuation_power') battery = dpwrap((BatteryDP(energy_density=100.0)), 'capacity', 'weight') times = dpwrap((Product(R_Time, R_Power, R_Energy)), ['mission_time', 'power'], 'energy') try: c1 = Connection('actuation', 'actuation_power', 'times', 'power') c2 = Connection('times', 'energy', 'battery', 'capacity') c3 = Connection('battery', 'weight', 'actuation', 'weight') dpconnect(dict(actuation=actuation, times=times, battery=battery), [c1, c2, c3]) except TheresALoop: pass
def call(self, opt, c): context = clone_context(c.context) ndp = opt.load_ndp(self.id_ndp) if not self.id_ndp in context.names: name = self.id_ndp else: name = context.new_name(prefix=self.id_ndp) context.add_ndp(name, ndp) con = Connection(self.cresource.dp, self.cresource.s, name, self.fname) context.add_connection(con) executed = c.executed + [self] # XXX forbidden = c.forbidden | set([self]) lower_bounds = dict(**c.lower_bounds) # get lower bounds for the new one lower_bounds_a = get_new_lowerbounds(context=context, name=name, lower_bounds=lower_bounds) for k, u in lower_bounds_a.items(): if len(u.minimals) == 0: msg = 'Unfeasible: %s' % (lower_bounds_a) raise Exception(msg) print('new lowerbounds: %s' % lower_bounds_a) for rname in ndp.get_rnames(): r = CResource(name, rname) if not r in lower_bounds_a: msg = 'Cannot find resource.' raise_desc(ValueError, msg, r=r, lower_bounds_a=lower_bounds_a) lower_bounds[r] = lower_bounds_a[r] del lower_bounds[self.cresource] from mcdp_opt.partial_result import get_lower_bound_ndp ndp, table = get_lower_bound_ndp(context) (_R, ur), _tableres = opt.get_lower_bounds(ndp, table) from mcdp_opt.optimization_state import OptimizationState s2 = OptimizationState(opt=opt, options=c.options, context=context, executed=executed, forbidden=forbidden, lower_bounds=lower_bounds, ur=ur, creation_order=opt.get_next_creation()) s2.info('Parent: #%s' % c.creation_order) s2.info('Action: #%s' % self) return s2
def check_compose2_loop2(): actuation = dpwrap(Mobility(), 'weight', 'actuation_power') battery = dpwrap((BatteryDP(energy_density=100.0)), 'capacity', 'battery_weight') times = dpwrap((Product(R_Time, R_Power, R_Energy)), ['mission_time', 'power'], 'energy') # 'times.power >= actuation.actuation_power', c1 = Connection('actuation', 'actuation_power', 'times', 'power') c2 = Connection('times', 'energy', 'battery', 'capacity') x = dpconnect(dict(actuation=actuation, times=times, battery=battery), [c1,c2]) y = dploop0(x, 'battery_weight', 'weight') print y.desc() assert y.get_fnames() == ['mission_time'], y.get_fnames() assert y.get_rnames() == ['battery_weight'], y.get_rnames() check_ftype(x, 'mission_time', R_Time) # check_ftype(x, 'weight', R_Weight) check_rtype(x, 'battery_weight', R_Weight_g) dp = y.get_dp() funsp = dp.get_fun_space() ressp = dp.get_res_space() print('funsp: %s' % funsp) print('ressp: %s' % ressp) assert funsp == R_Time, funsp assert ressp == R_Weight_g, ressp
def connect_resources_to_outside(name2ndp, connections, ndp_name, rnames): """ For each function in fnames of ndp_name, create a new outside function node and connect it to ndp_name. """ assert ndp_name in name2ndp ndp = name2ndp[ndp_name] if not set(rnames).issubset(ndp.get_rnames()): msg = 'Some of the resources are not present.' raise_desc(ValueError, msg, rnames=rnames, ndp=ndp) for rn in rnames: nn = get_name_for_res_node(rn) R = ndp.get_rtype(rn) name2ndp[nn] = dpwrap(Identity(R), rn, rn) connections.append(Connection(ndp_name, rn, nn, rn))
def connect_functions_to_outside(name2ndp, connections, ndp_name, fnames): """ For each function in fnames of ndp_name, create a new outside function node and connect it to ndp_name. """ assert ndp_name in name2ndp ndp = name2ndp[ndp_name] if not set(fnames).issubset(ndp.get_fnames()): msg = 'Some of the functions are not present.' raise_desc(ValueError, msg, fnames=fnames, ndp=ndp) for fname in fnames: F = ndp.get_ftype(fname) nn = get_name_for_fun_node(fname) name2ndp[nn] = dpwrap(Identity(F), fname, fname) connections.append(Connection(nn, fname, ndp_name, fname))
def call(self, opt, c): context = clone_context(c.context) con = Connection(self.cresource.dp, self.cresource.s, self.cfunction.dp, self.cfunction.s) context.add_connection(con) executed = c.executed + [self] # XXX forbidden = c.forbidden | set([self]) from mcdp_opt.partial_result import get_lower_bound_ndp ndp, table = get_lower_bound_ndp(context) (R, ur), tableres = opt.get_lower_bounds(ndp, table) lower_bounds = tableres from mcdp_opt.optimization_state import OptimizationState s2 = OptimizationState(opt=opt, options=c.options, context=context, executed=executed, forbidden=forbidden, lower_bounds=lower_bounds, ur=ur, creation_order=opt.get_next_creation()) return s2
def would_introduce_cycle(context, f, r): if f.dp == r.dp: return True from mocdp.comp.connection import get_connection_multigraph from networkx.algorithms.cycles import simple_cycles connections1 = list(context.connections) con = Connection(r.dp, r.s, f.dp, f.s) connections2 = connections1 + [con] G1 = get_connection_multigraph(connections1) G2 = get_connection_multigraph(connections2) cycles1 = list(simple_cycles(G1)) cycles2 = list(simple_cycles(G2)) c1 = len(cycles1) c2 = len(cycles2) # if c1 != c2: # print G2.edges() # print('c1: %s' % cycles1) # print('c2: %s' % cycles2) return c1 != c2
def filter_connections(c): if c.dp2 == name and c.s2 == fname: return Connection( c.dp1, c.s1, new_res_name, fname) else: return c
def translate_connections(c): if c.dp1 == name and c.s1 == rn: c = Connection(name, rn2, c.dp2, c.s2) return c
def cndp_flatten(ndp): check_isinstance(ndp, CompositeNamedDP) name2ndp = ndp.get_name2ndp() connections = ndp.get_connections() fnames = ndp.get_fnames() rnames = ndp.get_rnames() names2 = {} connections2 = [] proxy_functions = defaultdict(lambda: dict()) # proxy[name][fname] proxy_resources = defaultdict(lambda: dict()) for name, n0 in name2ndp.items(): # add empty (in case they have no functions/resources) proxy_functions[name] = {} proxy_resources[name] = {} n1 = n0.flatten() if isinstance(n1, CompositeNamedDP): nn = flatten_add_prefix(n1, prefix=name) else: nn = n1 if isinstance(nn, CompositeNamedDP): # nn_connections = nn.get_connections() for name2, ndp2 in nn.get_name2ndp().items(): assert not name2 in names2 isitf, is_fname = is_fun_node_name(name2) isitr, is_rname = is_res_node_name(name2) if (isitf or isitr): # connected_to_something = is_dp_connected(name2, nn_connections) # do not add the identity nodes # that represent functions or resources # except if they are unconnected # add_identities = not connected_to_something add_identities = True if not add_identities: # pragma: no cover continue else: # think of the case where there are a f and r with # same name if isitf: use_name = is_fname + '_f' if isitr: use_name = is_rname + '_r' assert not use_name in names2, use_name names2[use_name] = ndp2 if isitf: proxy_functions[name][is_fname] = ( use_name, ndp2.get_fnames()[0]) if isitr: proxy_resources[name][is_rname] = ( use_name, ndp2.get_rnames()[0]) else: assert not name2 in names2 names2[name2] = ndp2 for c in nn.get_connections(): # is it a connection to a function if False: isitf, fn = is_fun_node_name(c.dp1) isitr, rn = is_res_node_name(c.dp2) if isitf and isitr: # This is the case where there is a straight connection # from function to resource: # # f = instance mcdp { # provides a [dimensionless] # requires c [dimensionless] # # c >= a # } # In this case, we need to add an identity new_name = '_%s_pass_through_%s' % (name, c.s2) F = nn.get_name2ndp()[c.dp1].get_ftype(c.s1) ndp_pass = SimpleWrap(Identity(F), fnames=fn, rnames=rn) assert not new_name in names2 names2[new_name] = ndp_pass proxy_functions[name][fn] = (new_name, fn) proxy_resources[name][rn] = (new_name, rn) continue if isitf: proxy_functions[name][fn] = (c.dp2, c.s2) continue if isitr: proxy_resources[name][rn] = (c.dp1, c.s1) continue isitf, fn = is_fun_node_name(c.dp1) if isitf: dp1 = fn + '_f' assert dp1 in names2 else: dp1 = c.dp1 isitr, rn = is_res_node_name(c.dp2) if isitr: dp2 = rn + '_r' assert dp2 in names2 else: dp2 = c.dp2 assert dp1 in names2 assert dp2 in names2 assert c.s1 in names2[dp1].get_rnames() assert c.s2 in names2[dp2].get_fnames() c2 = Connection(dp1=dp1, s1=c.s1, dp2=dp2, s2=c.s2) connections2.append(c2) else: for fn in nn.get_fnames(): proxy_functions[name][fn] = (name, fn) for rn in nn.get_rnames(): proxy_resources[name][rn] = (name, rn) assert not name in names2 names2[name] = nn # check that these were correctly generated: # proxy_functions # proxy_resources def exploded(name): return isinstance(name2ndp[name], CompositeNamedDP) # print list(proxy_resources) errors = [] for name, n0 in name2ndp.items(): try: assert name in proxy_functions, name assert name in proxy_resources if exploded(name): for fname in n0.get_fnames(): newfname = "%s/%s" % (name, fname) assert newfname in proxy_functions[name], ( newfname, proxy_functions[name]) for rname in n0.get_rnames(): newrname = "%s/%s" % (name, rname) assert newrname in proxy_resources[name], ( newrname, proxy_resources[name]) else: for fname in n0.get_fnames(): assert fname in proxy_functions[name], ( fname, proxy_functions[name]) for rname in n0.get_rnames(): assert rname in proxy_resources[name] except Exception as e: # pragma: no cover s = '%s:\n %s %s \n\n%s' % (name, proxy_resources[name], proxy_functions[name], e) errors.append(s) if errors: # pragma: no cover s = "\n\n".join(errors) s += '%s %s' % (proxy_resources, proxy_functions) raise Exception(s) for c in connections: dp2 = c.dp2 s2 = c.s2 dp1 = c.dp1 s1 = c.s1 dp2_was_exploded = isinstance(name2ndp[dp2], CompositeNamedDP) if dp2_was_exploded: if not dp2 in proxy_functions: # pragma: no cover msg = 'Bug: cannot find dp2.' raise_desc(DPInternalError, msg, dp2=dp2, keys=list(proxy_functions), c=c) (dp2_, s2_) = proxy_functions[dp2]["%s/%s" % (dp2, s2)] if not dp2_ in names2: # pragma: no cover raise_desc(DPInternalError, "?", dp2_=dp2_, c=c, names2=sorted(names2)) else: dp2_ = dp2 s2_ = s2 dp1_was_exploded = isinstance(name2ndp[dp1], CompositeNamedDP) if dp1_was_exploded: (dp1_, s1_) = proxy_resources[dp1]["%s/%s" % (dp1, s1)] else: dp1_ = dp1 s1_ = s1 assert dp1_ in names2 assert s1_ in names2[dp1_].get_rnames(), (s1_, names2[dp1_].get_rnames()) assert dp2_ in names2 assert s2_ in names2[dp2_].get_fnames(), (s2_, names2[dp2_].get_fnames()) c2 = Connection(dp1=dp1_, s1=s1_, dp2=dp2_, s2=s2_) connections2.append(c2) ndp_res = CompositeNamedDP.from_parts(names2, connections2, fnames, rnames) ndp_simplified = simplify_identities(ndp_res) return ndp_simplified
def translate_connections(c): if c.dp2 == name and c.s2 == fn: c = Connection(c.dp1, c.s1, name, fn2) return c
def flatten_add_prefix(ndp, prefix): """ Adds a prefix for every node name and to functions/resources. """ if isinstance(ndp, SimpleWrap): dp = ndp.get_dp() fnames = ['%s%s%s' % (prefix, sep, _) for _ in ndp.get_fnames()] rnames = ['%s%s%s' % (prefix, sep, _) for _ in ndp.get_rnames()] icon = ndp.icon if len(fnames) == 1: fnames = fnames[0] if len(rnames) == 1: rnames = rnames[0] sw = SimpleWrap(dp, fnames=fnames, rnames=rnames, icon=icon) return sw if isinstance(ndp, CompositeNamedDP): def get_new_name(name2): isf, fname = is_fun_node_name(name2) isr, rname = is_res_node_name(name2) if isf: return get_name_for_fun_node('%s%s%s' % (prefix, sep, fname)) elif isr: return get_name_for_res_node('%s%s%s' % (prefix, sep, rname)) else: return "%s%s%s" % (prefix, sep, name2) def transform(name2, ndp2): # Returns name, ndp isf, fname = is_fun_node_name(name2) isr, rname = is_res_node_name(name2) if isf or isr: if isinstance(ndp2, SimpleWrap): if isf: fnames = "%s%s%s" % (prefix, sep, fname) rnames = "%s%s%s" % (prefix, sep, fname) if isr: fnames = "%s%s%s" % (prefix, sep, rname) rnames = "%s%s%s" % (prefix, sep, rname) dp = ndp2.dp res = SimpleWrap(dp=dp, fnames=fnames, rnames=rnames) elif isinstance(ndp2, LabelerNDP): ndp_inside = transform(name2, ndp2.ndp) return LabelerNDP(ndp_inside, ndp2.recursive_name) else: raise NotImplementedError(type(ndp2)) else: res = flatten_add_prefix(ndp2, prefix) return res names2 = {} connections2 = set() for name2, ndp2 in ndp.get_name2ndp().items(): name_ = get_new_name(name2) ndp_ = transform(name2, ndp2) assert not name_ in names2 names2[name_] = ndp_ for c in ndp.get_connections(): dp1, s1, dp2, s2 = c.dp1, c.s1, c.dp2, c.s2 dp1 = get_new_name(dp1) dp2 = get_new_name(dp2) s1_ = "%s%s%s" % (prefix, sep, s1) s2_ = "%s%s%s" % (prefix, sep, s2) assert s1_ in names2[dp1].get_rnames(), (s1_, names2[dp1].get_rnames()) assert s2_ in names2[dp2].get_fnames(), (s2_, names2[dp1].get_fnames()) c2 = Connection(dp1=dp1, s1=s1_, dp2=dp2, s2=s2_) connections2.add(c2) fnames2 = ['%s%s%s' % (prefix, sep, _) for _ in ndp.get_fnames()] rnames2 = ['%s%s%s' % (prefix, sep, _) for _ in ndp.get_rnames()] return CompositeNamedDP.from_parts(names2, connections2, fnames2, rnames2) if isinstance(ndp, NamedDPCoproduct): children = ndp.ndps children2 = tuple([flatten_add_prefix(_, prefix) for _ in children]) labels2 = ndp.labels return NamedDPCoproduct(children2, labels2) if isinstance(ndp, LabelerNDP): x = flatten_add_prefix(ndp.ndp, prefix) return LabelerNDP(x, ndp.recursive_name) assert False, type(ndp)
def f(c): key = (c.dp1, c.s1) dp1, s1 = res_map.get(key, key) key = (c.dp2, c.s2) dp2, s2 = fun_map.get(key, key) return Connection(dp1=dp1, s1=s1, dp2=dp2, s2=s2)
def simplify_identities(ndp): """ Removes the identites from the NDP. Useful for visualization. """ def can_simplify(child): if len(child.get_fnames()) != 1: return False if len(child.get_rnames()) != 1: return False if not isinstance(child, SimpleWrap): return False if not isinstance(child.dp, IdentityDP): return False return True try: ndp.check_fully_connected() connected = True except NotConnected: connected = False ndp = ndp.__copy__() for name, child in list(cndp_get_name_ndp_notfunres(ndp)): if not can_simplify(child): continue # (prev) -> (name) -> (succ) prev = succ = None # prevs = [] # succs = [] for c in ndp.context.connections: if c.dp2 == name: prev = c.dp1 prev_s = c.s1 # prevs.append((c.dp1, c.s1)) if c.dp1 == name: succ = c.dp2 succ_s = c.s2 # succs.append((c.dp2, c.s2)) # it has exactly 1 forward and 1 succ connections, # not to itself ok = prev is not None and succ is not None and prev != succ if not ok: continue # remove those two connections = [ c for c in ndp.context.connections if c.dp1 != name and c.dp2 != name ] ndp.context.connections = connections c = Connection(dp1=prev, s1=prev_s, dp2=succ, s2=succ_s) ndp.context.add_connection(c) del ndp.context.names[name] res = ndp.__copy__() if connected: try: res.check_fully_connected() except NotConnected as e: msg = 'Result is not fully connected.' raise_wrapped( DPInternalError, e, msg, # res=res.repr_long(), compact=True) return res
def cndp_makecanonical(ndp, name_inner_muxed='_inner_muxed', s_muxed='_muxed'): """ Returns a composite with only one ndp, called <named_inner_muxed>. If there were cycles, then this will also have a signal caled s_muxed and there will be one connection to it. raises DPSemanticErrorNotConnected """ assert isinstance(ndp, CompositeNamedDP), type(ndp) try: ndp.check_fully_connected() except NotConnected as e: msg = 'Cannot put in canonical form because not all subproblems are connected.' raise_wrapped(DPSemanticErrorNotConnected, e, msg, compact=True) fnames = ndp.get_fnames() rnames = ndp.get_rnames() # First, we flatten it ndp = cndp_flatten(ndp) assert ndp.get_fnames() == fnames assert ndp.get_rnames() == rnames # then we compact it (take the product of edges) # Note also that this abstract() the children; # however, because we flattened before, this is redundant, # as every DP is a SimpleDP ndp = ndp.compact() assert ndp.get_fnames() == fnames assert ndp.get_rnames() == rnames # Check that we have some cycles G = get_connection_multigraph(ndp.get_connections()) cycles = list(simple_cycles(G)) if not cycles: ndp_inner = ndp cycles_names = [] else: # then we choose which edges to remove connections_to_cut = choose_connections_to_cut( connections=ndp.get_connections(), name2dp=ndp.get_name2ndp()) connections_to_cut = list(connections_to_cut) n = len(connections_to_cut) cycles_names = list(['cut%d' % _ for _ in range(n)]) ndp_inner = cndp_create_one_without_some_connections( ndp, connections_to_cut, cycles_names) assert ndp_inner.get_fnames() == fnames + cycles_names assert ndp_inner.get_rnames() == rnames + cycles_names if cycles_names: ndp_inner_muxed = add_muxes(ndp_inner, cs=cycles_names, s_muxed=s_muxed) mux_signal = s_muxed assert ndp_inner_muxed.get_fnames() == fnames + [mux_signal] assert ndp_inner_muxed.get_rnames() == rnames + [mux_signal] else: ndp_inner_muxed = ndp_inner name2ndp = {} name2ndp[name_inner_muxed] = ndp_inner_muxed connections = [] connect_functions_to_outside(name2ndp, connections, ndp_name=name_inner_muxed, fnames=fnames) connect_resources_to_outside(name2ndp, connections, ndp_name=name_inner_muxed, rnames=rnames) if cycles_names: connections.append( Connection(name_inner_muxed, mux_signal, name_inner_muxed, mux_signal)) outer = CompositeNamedDP.from_parts(name2ndp=name2ndp, connections=connections, fnames=fnames, rnames=rnames) return outer
def filter_connections(c): if c.dp1 == name and c.s1 == rname: return Connection(new_fun_name, rname, c.dp2, c.s2) else: return c
def add_muxes(inner, cs, s_muxed, inner_name='_inner0', mux1_name='_mux1', mux2_name='_mux2'): """ Add muxes before and after inner ---(extraf)--| |---(extrar)-- |--c1-----| inner |--c1--| s_muxed-|--c2-----| |--c2--|--s_muxed """ extraf = [f for f in inner.get_fnames() if not f in cs] extrar = [r for r in inner.get_rnames() if not r in cs] fnames = extraf + [s_muxed] rnames = extrar + [s_muxed] name2ndp = {} connections = [] name2ndp[inner_name] = inner # Second mux if len(cs) == 1: F = inner.get_ftype(cs[0]) nto1 = SimpleWrap(Identity(F), fnames=cs[0], rnames=s_muxed) else: types = inner.get_ftypes(cs) F = PosetProduct(types.subs) # [0, 1, 2] coords = list(range(len(cs))) mux = Mux(F, coords) nto1 = SimpleWrap(mux, fnames=cs, rnames=s_muxed) if len(cs) == 1: R = inner.get_rtype(cs[0]) _1ton = SimpleWrap(Identity(R), fnames=s_muxed, rnames=cs[0]) else: # First mux coords = list(range(len(cs))) R = mux.get_res_space() mux2 = Mux(R, coords) _1ton = SimpleWrap(mux2, fnames=s_muxed, rnames=cs) F2 = mux2.get_res_space() tu = get_types_universe() tu.check_equal(F, F2) name2ndp[mux1_name] = nto1 name2ndp[mux2_name] = _1ton for n in cs: connections.append(Connection(inner_name, n, mux1_name, n)) for n in cs: connections.append(Connection(mux2_name, n, inner_name, n)) # Now add the remaining names connect_functions_to_outside(name2ndp, connections, ndp_name=inner_name, fnames=extraf) connect_resources_to_outside(name2ndp, connections, ndp_name=inner_name, rnames=extrar) connect_resources_to_outside(name2ndp, connections, ndp_name=mux1_name, rnames=[s_muxed]) connect_functions_to_outside(name2ndp, connections, ndp_name=mux2_name, fnames=[s_muxed]) outer = CompositeNamedDP.from_parts(name2ndp=name2ndp, connections=connections, fnames=fnames, rnames=rnames) return outer