def rewrite(clusters, mode='advanced'): """ Transform N :class:`Cluster` objects of SymPy expressions into M :class:`Cluster` objects of SymPy expressions with reduced operation count, with M >= N. :param clusters: The clusters to be transformed. :param mode: drive the expression transformation The ``mode`` parameter recognises the following values: :: * 'noop': Do nothing. * 'basic': Apply common sub-expressions elimination. * 'advanced': Apply all transformations that will reduce the operation count w/ minimum increase to the memory pressure, namely 'basic', factorization, CSRE for time-invariants only. * 'speculative': Like 'advanced', but apply CSRE also to time-varying sub-expressions, which might further increase the memory pressure. * 'aggressive': Like 'speculative', but apply CSRE to any non-trivial sub-expression (i.e., anything that is at least in a sum-of-products form). This may substantially increase the memory pressure. """ if not (mode is None or isinstance(mode, str)): raise ValueError("Parameter 'mode' should be a string, not %s." % type(mode)) if mode is None or mode == 'noop': return clusters processed = ClusterGroup() for cluster in clusters: if cluster.is_dense: if mode in modes: processed.extend(modes[mode]().run(cluster)) else: try: processed.extend(CustomRewriter().run(cluster)) except DSEException: dse_warning("Unknown rewrite mode(s) %s" % mode) processed.append(cluster) else: # Downgrade sparse clusters to basic rewrite mode since it's # pointless to expose loop-redundancies when the iteration space # only consists of a few points processed.extend(BasicRewriter(False).run(cluster)) return groupby(processed)
def rewrite(clusters, mode='advanced'): """ Transform N :class:`Cluster` objects of SymPy expressions into M :class:`Cluster` objects of SymPy expressions with reduced operation count, with M >= N. :param clusters: The clusters to be transformed. :param mode: drive the expression transformation The ``mode`` parameter recognises the following values: :: * 'noop': Do nothing. * 'basic': Apply common sub-expressions elimination. * 'advanced': Apply all transformations that will reduce the operation count w/ minimum increase to the memory pressure, namely 'basic', factorization, CIRE for time-invariants only. * 'speculative': Like 'advanced', but apply CIRE also to time-varying sub-expressions, which might further increase the memory pressure. * 'aggressive': Like 'speculative', but apply CIRE to any non-trivial sub-expression (i.e., anything that is at least in a sum-of-products form). This may substantially increase the memory pressure. """ if not (mode is None or isinstance(mode, str)): raise ValueError("Parameter 'mode' should be a string, not %s." % type(mode)) if mode is None or mode == 'noop': return clusters elif mode not in modes: dse_warning("Unknown rewrite mode(s) %s" % mode) return clusters # Separate rewriters for dense and sparse clusters; sparse clusters have # non-affine index functions, thus making it basically impossible, in general, # to apply the more advanced DSE passes. # Note: the sparse rewriter uses the same template for temporaries as # the dense rewriter, thus temporaries are globally unique rewriter = modes[mode]() fallback = BasicRewriter(False, rewriter.template) processed = ClusterGroup( flatten( rewriter.run(c) if c.is_dense else fallback.run(c) for c in clusters)) return groupby(processed).finalize()
def rewrite(clusters, mode='advanced'): """ Transform N :class:`Cluster`s of SymPy expressions into M :class:`Cluster`s of SymPy expressions with reduced operation count, with M >= N. :param clusters: The clusters to be transformed. :param mode: drive the expression transformation as follows: :: * 'noop': Do nothing. * 'basic': Apply common sub-expressions elimination. * 'factorize': Apply heuristic factorization of temporaries. * 'approx-trigonometry': Replace expensive trigonometric functions with suitable polynomial approximations. * 'glicm': Heuristically hoist time-invariant and cross-stencil redundancies. * 'advanced': Compose all known transformations. """ if not mode: return clusters elif isinstance(mode, str): mode = set([mode]) else: try: mode = set(mode) except TypeError: dse_warning("Arg mode must be str or tuple (got %s)" % type(mode)) return clusters if 'noop' in mode: return clusters elif mode.isdisjoint(set(modes)): dse_warning("Unknown rewrite mode(s) %s" % str(mode)) return clusters else: processed = [] for cluster in clusters: if cluster.is_dense: rewriter = Rewriter(mode) else: # Downgrade sparse clusters to basic rewrite mode since it's # pointless to expose loop-redundancies when the iteration space # only consists of a few points rewriter = Rewriter(set(['basic']), False) processed.extend(rewriter.run(cluster)) return processed
def rewrite(clusters, mode='advanced'): """ Given a sequence of N Clusters, produce a sequence of M Clusters with reduced operation count, with M >= N. Parameters ---------- clusters : list of Cluster The Clusters to be transformed. mode : str, optional The aggressiveness of the rewrite. Accepted: - ``noop``: Do nothing. - ``basic``: Apply common sub-expressions elimination. - ``advanced``: Apply all transformations that will reduce the operation count w/ minimum increase to the memory pressure, namely 'basic', factorization, CIRE for time-invariants only. - ``speculative``: Like 'advanced', but apply CIRE also to time-varying sub-expressions, which might further increase the memory pressure. * ``aggressive``: Like 'speculative', but apply CIRE to any non-trivial sub-expression (i.e., anything that is at least in a sum-of-product form). Further, seek and drop cross-cluster redundancies (this is the only pass that attempts to optimize *across* clusters, rather than within a cluster). The 'aggressive' mode may substantially increase the symbolic processing time; it may or may not reduce the JIT-compilation time; it may or may not improve the overall runtime performance. """ if not (mode is None or isinstance(mode, str)): raise ValueError("Parameter 'mode' should be a string, not %s." % type(mode)) if mode is None or mode == 'noop': return clusters elif mode not in modes: dse_warning("Unknown rewrite mode(s) %s" % mode) return clusters # 1) Local optimization # --------------------- # We use separate rewriters for dense and sparse clusters; sparse clusters have # non-affine index functions, thus making it basically impossible, in general, # to apply the more advanced DSE passes. # Note: the sparse rewriter uses the same template for temporaries as # the dense rewriter, thus temporaries are globally unique rewriter = modes[mode]() fallback = BasicRewriter(False, rewriter.template) processed = ClusterGroup( flatten( rewriter.run(c) if c.is_dense else fallback.run(c) for c in clusters)) # 2) Cluster grouping # ------------------- # Different clusters may have created new (smaller) clusters which are # potentially groupable within a single cluster processed = groupby(processed) # 3)Global optimization # --------------------- # After grouping, there may be redundancies in one or more clusters. This final # pass searches and drops such redundancies if mode == 'aggressive': processed = cross_cluster_cse(processed) return processed.finalize()