diff --git a/islpy/__init__.py b/islpy/__init__.py index 2d05572602b40d1633986c68c262fe311a104796..7998b2e481f3e916305c35b5a262f446b3ebae6f 100644 --- a/islpy/__init__.py +++ b/islpy/__init__.py @@ -129,6 +129,27 @@ EXPR_CLASSES = tuple(cls for cls in ALL_CLASSES if "Aff" in cls.__name__ or "Polynomial" in cls.__name__) +def _runs_in_integer_set(s, max_int=None): + if max_int is None: + max_int = max(s) + + i = 0 + while i < max_int: + if i in s: + start = i + + i += 1 + while i < max_int and i in s: + i += 1 + + end = i + + yield (start, end-start) + + else: + i += 1 + + def _add_functionality(): # {{{ Context @@ -1185,4 +1206,57 @@ def align_two(obj1, obj2, across_dim_types=False): return (obj1, obj2) +# {{{ performance tweak for dim_{min,max}: project first + +def _find_noninteracting_dims(obj, dt, idx, other_dt): + candidate_dims = set(range(obj.dim(other_dt))) + + if isinstance(obj, BasicSet): + basics = [obj] + elif isinstance(obj, Set): + basics = obj.get_basic_sets() + elif isinstance(obj, BasicMap): + basics = [obj] + elif isinstance(obj, Map): + basics = obj.get_basic_maps() + else: + raise TypeError("unsupported arg type '%s'" % type(obj)) + + for bs in basics: + for c in bs.get_constraints(): + if not c.involves_dims(dt, idx, 1): + continue + + found_interacting = set() + + for dim in candidate_dims: + if c.involves_dims(other_dt, dim, 1): + found_interacting.add(dim) + + candidate_dims -= found_interacting + + return candidate_dims + + +def _project_out_noninteracting(obj, dt, idx, other_dt): + nonint = _find_noninteracting_dims(obj, dt, idx, other_dt) + + for first, n in reversed(list(_runs_in_integer_set(nonint))): + obj = obj.project_out(other_dt, first, n) + + return obj + + +def dim_min_projected(obj, idx): + obj = _project_out_noninteracting(obj, dim_type.out, idx, dim_type.param) + return obj.dim_min(idx) + + +def dim_max_projected(obj, idx): + obj = _project_out_noninteracting(obj, dim_type.out, idx, dim_type.param) + return obj.dim_max(idx) + +# }}} + + # vim: foldmethod=marker