From 00f0b96b00f9bdafce94180170f427bc57883bb0 Mon Sep 17 00:00:00 2001
From: Andreas Kloeckner <inform@tiker.net>
Date: Mon, 5 Nov 2012 23:54:49 -0500
Subject: [PATCH] Implement (untested) link_inames.

---
 MEMO              |  6 ++++
 doc/reference.rst |  6 ++++
 loopy/__init__.py | 87 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 99 insertions(+)

diff --git a/MEMO b/MEMO
index 75c9f6a53..9c603fd58 100644
--- a/MEMO
+++ b/MEMO
@@ -48,6 +48,12 @@ To-do
 
 - Kernel fusion
 
+- rename iname
+
+- delete unused inames
+
+- link_inames
+
 - ExpandingIdentityMapper
   extract_subst -> needs WalkMapper
   padding
diff --git a/doc/reference.rst b/doc/reference.rst
index af2ea1bbe..e066ba1df 100644
--- a/doc/reference.rst
+++ b/doc/reference.rst
@@ -163,6 +163,12 @@ Wrangling inames
 
 .. autofunction:: duplicate_inames
 
+.. autofunction:: link_inames
+
+.. autofunction:: rename_inames
+
+.. autofunction:: delete_unused_inames
+
 Dealing with Substitution Rules
 -------------------------------
 
diff --git a/loopy/__init__.py b/loopy/__init__.py
index ac78736d2..84f054a5a 100644
--- a/loopy/__init__.py
+++ b/loopy/__init__.py
@@ -527,6 +527,7 @@ def duplicate_inames(knl, inames, within, new_inames=None, suffix=None,
         knl = knl.copy(
                 domains=domch.get_domains_with(
                     duplicate_axes(domch.domain, [old_iname], [new_iname])))
+
     # }}}
 
     # {{{ change the inames in the code
@@ -552,6 +553,92 @@ def duplicate_inames(knl, inames, within, new_inames=None, suffix=None,
 
 # }}}
 
+# {{{ link inames
+
+def link_inames(knl, inames, new_iname, within=None, tag=None):
+    # {{{ normalize arguments
+
+    if isinstance(inames, str):
+        inames = inames.split(",")
+
+    new_iname = knl.get_var_name_generator()(new_iname)
+
+    # }}}
+
+    # {{{ ensure that each iname is used at most once in each instruction
+
+    inames_set = set(inames)
+
+    for insn in knl.instructions:
+        insn_inames = knl.insn_inames(insn.id) | insn.reduction_inames()
+
+        if len(insn_inames & inames_set) > 1:
+            raise RuntimeError("To-be-linked inames '%s' are used in "
+                    "instruction '%s'. No more than one such iname can "
+                    "be used in one instruction."
+                    % (", ".join(insn_inames & inames_set), insn.id))
+
+    # }}}
+
+    from loopy.kernel import DomainChanger
+    domch = DomainChanger(knl, inames)
+
+    # {{{ ensure that projections are identical
+
+    unrelated_dom_inames = list(
+            set(domch.domain.get_var_names(dim_type.set))
+            - inames_set)
+
+    projections = [
+            domch.domain.project_out_except(unrelated_dom_inames + [iname], dim_type.set)
+            for iname in inames]
+
+    from pytools import all_equal
+    if not all_equal(projections):
+        raise RuntimeError("Inames cannot be linked because their domain "
+                "constraints are not the same.")
+
+    # }}}
+
+    # change the domain
+    from loopy.isl_helpers import duplicate_axes
+    knl = knl.copy(
+            domains=domch.get_domains_with(
+                duplicate_axes(domch.domain, [inames[0]], [new_iname])))
+
+    # {{{ change the code
+
+    subst_dict = dict((iname, new_iname) for iname in inames)
+
+    from loopy.context_matching import parse_stack_match
+    within = parse_stack_match(within)
+
+    from pymbolic.mapper.substitutor import make_subst_func
+    ijoin = ExpandingSubstitutionMapper(knl, within,
+            make_subst_func(subst_dict))
+
+    knl = ijoin.map_kernel(knl)
+
+    # }}}
+
+    knl = knl.delete_unused_inames(knl, inames)
+
+    if tag is not None:
+        knl = tag_inames(knl, {new_iname: tag})
+
+    return knl
+
+# }}}
+
+# {{{ delete unused inames
+
+def delete_unused_inames(knl, inames=None):
+    from warnings import warn
+    warn("delete_unused_inames is unimplemented")
+    return knl
+
+# }}}
+
 # {{{ convenience: add_prefetch
 
 # {{{ process footprint_subscripts
-- 
GitLab