def simplify_indices_F(F, coords): # Safety check: Clearly if it's not the identity it cannot be equal to () R = get_R_from_F_coords(F, coords) if not (R == F): return coords # generic test i0 = get_id_indices(F) # compose i0coords = compose_indices(F, i0, coords, list) if i0 == i0coords: return () mcdp_dev_warning( 'simplify_indices_F(): Note that none of this is ever taken(!).') if coords == [0] and len(F) == 1: return () if coords == [0, 1] and len(F) == 2: return () if coords == [0, (1, )] and len(F) == 2: return () if coords == [0, 1, 2] and len(F) == 3: return () mcdp_dev_warning('need a double check here') if coords == [[(0, 0)], [(1, 0)]]: return () if coords == [[(0, 0)], [(1, 0), (1, 1)]]: return () # [[(0, 1)], [(1, 0), (0, 0)]] return coords
def _execute(self, dp1, dp2): from mcdp_dp.dp_series_simplification import unwrap_as_series_start_last dp2_start, dp2_last = unwrap_as_series_start_last(dp2) a = dp2_last.coords R = Parallel(dp1, dp2_start).get_res_space() coords0 = compose_indices(R, 1, a, list) coords = [0, coords0] m = Mux(R, coords) x = make_parallel(dp1, dp2_start) from .dp_series_simplification import make_series return make_series(x, m)
def mux_composition(dp1, dp2): try: dp0 = Series(dp1, dp2) F = dp1.get_fun_space() c1 = dp1.coords c2 = dp2.coords coords = compose_indices(F, c1, c2, list) coords = simplify_indices_F(F, coords) res = Mux(F, coords) assert res.get_res_space() == dp0.get_res_space() return res except DPInternalError as e: # pragma: no cover msg = 'Cannot create shortcut.' raise_wrapped(DPInternalError, e, msg, dp1=dp1.repr_long(), dp2=dp2.repr_long())
def make_series(dp1, dp2): """ Creates a Series if needed. Simplifies the identity and muxes """ if disable_optimization: # pragma: no cover return Series(dp1, dp2) # first, check that the series would be created correctly # Series(X(F,R), Terminator(R)) => Terminator(F) # but X not loop # if is_equiv_to_terminator(dp2) and isinstance(dp1, Mux): # res = Terminator(dp1.get_fun_space()) # assert res.get_fun_space() == dp1.get_fun_space() # return res if equiv_to_identity(dp1): return dp2 if equiv_to_identity(dp2): return dp1 if isinstance(dp1, Parallel) and isinstance(dp2, Parallel): a = make_series(dp1.dp1, dp2.dp1) b = make_series(dp1.dp2, dp2.dp2) return make_parallel(a, b) # TODO: comment this, you get an error if isinstance(dp1, Mux) and isinstance(dp2, Mux): return mux_composition(dp1, dp2) if isinstance(dp1, Mux): def has_null_fun(dp): F = dp.get_fun_space() return isinstance(F, PosetProduct) and len(F) == 0 if isinstance(dp2, Parallel): if isinstance(dp2.dp1, Identity) and has_null_fun(dp2.dp1): assert len( dp1.coords) == 2 # because it is followed by parallel assert dp1.coords[0] == [] # because it's null x = dp1.coords[1] A = Mux(dp1.get_fun_space(), x) B = dp2.dp2 C = Mux(B.get_res_space(), [[], ()]) return make_series(make_series(A, B), C) if isinstance(dp2.dp2, Identity) and has_null_fun(dp2.dp2): assert len( dp1.coords) == 2 # because it is followed by parallel assert dp1.coords[1] == [] # because it's null x = dp1.coords[0] A = Mux(dp1.get_fun_space(), x) B = dp2.dp1 C = Mux(B.get_res_space(), [(), []]) return make_series(make_series(A, B), C) if isinstance(dp2, Series): dps = unwrap_series(dp2) def has_null_identity(dp): assert isinstance(dp, Parallel) if isinstance(dp.dp1, Identity) and has_null_fun(dp.dp1): return True if isinstance(dp.dp2, Identity) and has_null_fun(dp.dp2): return True return False if isinstance(dps[0], Parallel) and has_null_identity(dps[0]): first = make_series(dp1, dps[0]) rest = reduce(make_series, dps[1:]) return make_series(first, rest) # bring the mux outside the parallel # | - Mux(c) - p1 # Mux([a,b]) ----> | # | - # | - p1 # Mux([a*c,b]) ----> | # | if isinstance(dp1, Mux) and isinstance(dp2, Parallel) \ and isinstance(unwrap_series(dp2.dp1)[0], Mux): unwrapped = unwrap_series(dp2.dp1) first_mux = unwrapped[0] assert isinstance(first_mux, Mux) coords = dp1.coords assert isinstance(coords, list) and len(coords) == 2, coords F = dp1.get_fun_space() coords2 = [ compose_indices(F, coords[0], first_mux.coords, list), coords[1] ] m2 = Mux(F, coords2) rest = wrap_series(first_mux.get_res_space(), unwrapped[1:]) res = make_series(m2, make_parallel(rest, dp2.dp2)) if do_extra_checks(): check_same_spaces(Series(dp1, dp2), res) return res if isinstance(dp1, Mux) and isinstance(dp2, Parallel) \ and isinstance(unwrap_series(dp2.dp2)[0], Mux): unwrapped = unwrap_series(dp2.dp2) first_mux = unwrapped[0] assert isinstance(first_mux, Mux) coords = dp1.coords assert isinstance(coords, list) and len(coords) == 2, coords F = dp1.get_fun_space() coords2 = [ coords[0], compose_indices(F, coords[1], first_mux.coords, list) ] m2 = Mux(F, coords2) rest = wrap_series(first_mux.get_res_space(), unwrapped[1:]) res = make_series(m2, make_parallel(dp2.dp1, rest)) if do_extra_checks(): check_same_spaces(Series(dp1, dp2), res) return res # print('Cannot simplify:') # print(' dp1: %s' % dp1) # print(' dp2: %s' % dp2) # print('\n- '.join([str(x) for x in unwrap_series(a)])) dp1s = unwrap_series(dp1) dp2s = unwrap_series(dp2) for rule in rules: # [dp1s[:-1] dp1s[-1]] --- [dp2s[0] dp2s[1:]] if rule.applies(dp1s[-1], dp2s[0]): # logger.debug('Applying series simplification rule %s' % type(rule).__name__) r = rule.execute(dp1s[-1], dp2s[0]) try: check_same_fun(r, dp1s[-1]) check_same_res(r, dp2s[0]) except Exception as e: msg = 'Invalid result of simplification rule.' raise_wrapped(DPInternalError, e, msg, rule=rule, result=r.repr_long()) first = wrap_series(dp1.get_fun_space(), dp1s[:-1]) rest = wrap_series(dp2s[0].get_fun_space(), dp2s[1:]) return make_series(first, make_series(r, rest)) return Series(dp1, dp2)