nitg-s: cleaned AbstractColoring::colorize method
[nit.git] / src / coloring.nit
index 043a10b..9263329 100644 (file)
@@ -19,56 +19,29 @@ import rapid_type_analysis # for type coloration
 
 abstract class AbstractColoring[E: Object]
 
-       private var sorter: AbstractSorter[E]
-       private var reverse_sorter: AbstractSorter[E]
-
-       private var core: OrderedSet[E] = new OrderedSet[E]
-       private var crown: OrderedSet[E] = new OrderedSet[E]
-       private var border: OrderedSet[E] = new OrderedSet[E]
+       private var core: Set[E] = new HashSet[E]
+       private var crown: Set[E] = new HashSet[E]
+       private var border: Set[E] = new HashSet[E]
 
        private var coloration_result: Map[E, Int] = new HashMap[E, Int]
-       private var conflicts_graph_cache: nullable HashMap[E, Set[E]]
-
-       init(sorter: AbstractSorter[E], reverse_sorter: AbstractSorter[E]) do
-               self.sorter = sorter
-               self.reverse_sorter = reverse_sorter
-       end
 
-       fun colorize(elements: Collection[E]): Map[E, Int] do
-               # tag each element as part of group core, crown or border
-               for e in elements do
-                       tag_element(e)
-               end
-
-               #print "core: {core.join(", ")}"
-               #print "border: {border.join(", ")}"
-               #print "crown: {crown.join(", ")}"
-
-               # sort by reverse linearization order
-               reverse_sorter.sort(core)
-               reverse_sorter.sort(border)
-               reverse_sorter.sort(crown)
-
-               #print "conflicts"
-               #for k, v in conflicts_graph do
-               #       if k isa MType then
-               #               print "{k}: {v.join(", ")}"
-               #       end
-               #end
+       init do end
 
-               # colorize graph
+       fun colorize(elements: Set[E]): Map[E, Int] do
+               tag_elements(elements)
+               build_conflicts_graph
                colorize_elements(core)
                colorize_elements(border)
                colorize_elements(crown)
-
                return coloration_result
        end
 
        # Colorize a collection of elements
-       private fun colorize_elements(elements: Collection[E]) do
+       private fun colorize_elements(elements: Set[E]) do
                var min_color = 0
 
-               for element in elements do
+               var lin = reverse_linearize(elements)
+               for element in lin do
                        var color = min_color
                        while not self.is_color_free(element, color) do
                                color += 1
@@ -91,89 +64,87 @@ abstract class AbstractColoring[E: Object]
                return true
        end
 
-       # Tag element as core, crown or border
-       private fun tag_element(element: E) do
-               # Check if sub elements are all in single inheritance
-               var all_subelements_si = true
-               for subelem in self.sub_elements(element) do
-                       if self.is_element_mi(subelem) then
-                               all_subelements_si = false
-                               break
+       # Tag elements as core, crown or border
+       private fun tag_elements(elements: Set[E]) do
+               for element in elements do
+                       # Check if sub elements are all in single inheritance
+                       var all_subelements_si = true
+                       for subelem in self.sub_elements(element) do
+                               if self.is_element_mi(subelem) then
+                                       all_subelements_si = false
+                                       break
+                               end
                        end
-               end
 
-               # Tag as core, crown or border
-               if self.is_element_mi(element) then
-                       core.add_all(self.super_elements(element))
-                       core.add(element)
-                       if all_subelements_si then
-                               border.add(element)
+                       # Tag as core, crown or border
+                       if self.is_element_mi(element) then
+                               core.add_all(self.super_elements(element))
+                               core.add(element)
+                               if all_subelements_si then
+                                       border.add(element)
+                               end
+                       else if not all_subelements_si then
+                               core.add_all(self.super_elements(element))
+                               core.add(element)
+                       else
+                               crown.add(element)
                        end
-               else if not all_subelements_si then
-                       core.add_all(self.super_elements(element))
-                       core.add(element)
-               else
-                       crown.add(element)
                end
        end
 
        # Conflicts graph of elements hierarchy (two types are in conflict if they have common subelements)
-       private fun conflicts_graph: Map[E, Set[E]] do
-               if self.conflicts_graph_cache == null then
-                       self.conflicts_graph_cache = new HashMap[E, HashSet[E]]
-                       for t in self.core do
-                               for i in self.linear_extension(t) do
-                                       if t == i then continue
-
-                                       var lin_i = self.linear_extension(i)
-
-                                       for j in self.linear_extension(t) do
-                                               if i == j or j == t then continue
-                                               var lin_j = self.linear_extension(j)
-
-                                               var d_ij = lin_i - lin_j
-                                               var d_ji = lin_j - lin_i
-
-                                               for ed1 in d_ij do
-                                                       if not conflicts_graph_cache.has_key(ed1) then conflicts_graph_cache[ed1] = new HashSet[E]
-                                                       # add ed1 x ed2 to conflicts graph
-                                                       for ed2 in d_ji do conflicts_graph_cache[ed1].add(ed2)
-                                               end
-                                               for ed1 in d_ij do
-                                                       if not conflicts_graph_cache.has_key(ed1) then conflicts_graph_cache[ed1] = new HashSet[E]
-                                                       # add ed1 x ed2 to conflicts graph
-                                                       for ed2 in d_ji do conflicts_graph_cache[ed1].add(ed2)
-                                               end
+       private fun build_conflicts_graph do
+               self.conflicts_graph = new HashMap[E, HashSet[E]]
+               var core = reverse_linearize(self.core)
+               for t in core do
+                       for i in self.linear_extension(t) do
+                               if t == i then continue
+
+                               var lin_i = self.linear_extension(i)
+
+                               for j in self.linear_extension(t) do
+                                       if i == j or j == t then continue
+                                       var lin_j = self.linear_extension(j)
+
+                                       var d_ij = lin_i - lin_j
+                                       var d_ji = lin_j - lin_i
+
+                                       for ed1 in d_ij do
+                                               if not conflicts_graph.has_key(ed1) then conflicts_graph[ed1] = new HashSet[E]
+                                               # add ed1 x ed2 to conflicts graph
+                                               for ed2 in d_ji do conflicts_graph[ed1].add(ed2)
+                                       end
+                                       for ed1 in d_ij do
+                                               if not conflicts_graph.has_key(ed1) then conflicts_graph[ed1] = new HashSet[E]
+                                               # add ed1 x ed2 to conflicts graph
+                                               for ed2 in d_ji do conflicts_graph[ed1].add(ed2)
                                        end
                                end
                        end
                end
-               return conflicts_graph_cache.as(not null)
        end
 
+       private var conflicts_graph: nullable HashMap[E, Set[E]]
+
        # cache for linear_extensions
-       private var linear_extensions_cache: Map[E, OrderedSet[E]] = new HashMap[E, OrderedSet[E]]
+       private var linear_extensions_cache: Map[E, Array[E]] = new HashMap[E, Array[E]]
 
        # Return a linear_extension of super_elements of the element
-       private fun linear_extension(element: E): OrderedSet[E] do
+       private fun linear_extension(element: E): Array[E] do
                if not self.linear_extensions_cache.has_key(element) then
-                       var lin = new OrderedSet[E]
-                       lin.add(element)
-                       lin.add_all(self.super_elements(element))
-                       self.sorter.sort(lin)
-                       self.linear_extensions_cache[element] = lin
+                       var supers = new HashSet[E]
+                       supers.add(element)
+                       supers.add_all(self.super_elements(element))
+                       self.linear_extensions_cache[element] = self.linearize(supers)
                end
                return self.linear_extensions_cache[element]
        end
 
-       # Return all super elements (directs and indirects) of an element
-       private fun super_elements(element: E): Collection[E] is abstract
-
-       # Return all sub elements (directs and indirects) of an element
-       private fun sub_elements(element: E): Collection[E] is abstract
-
-       # Is the element in multiple inheritance ?
+       private fun super_elements(element: E): Set[E] is abstract
+       private fun sub_elements(element: E): Set[E] is abstract
        private fun is_element_mi(element: E): Bool is abstract
+       private fun linearize(elements: Set[E]): Array[E] is abstract
+       private fun reverse_linearize(elements: Set[E]): Array[E] is abstract
 end
 
 # MClassType coloring
@@ -185,12 +156,7 @@ class TypeColoring
        private var mmodule: MModule
        private var mtypes: Set[T]
 
-       # caches
-       private var super_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
-       private var sub_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
-
        init(mainmodule: MModule, mtypes: Set[T]) do
-               super(new TypeSorter(mainmodule), new ReverseTypeSorter(mainmodule))
                self.mmodule = mainmodule
                self.mtypes = mtypes
        end
@@ -218,39 +184,11 @@ class TypeColoring
                return tables
        end
 
-       redef fun super_elements(element) do
-               if not self.super_elements_cache.has_key(element) then
-                       var supers = new HashSet[T]
-                       for mtype in self.mtypes do
-                               if element == mtype then continue
-                               if element.is_subtype(self.mmodule, null, mtype) then
-                                       supers.add(mtype)
-                               end
-                       end
-                       self.super_elements_cache[element] = supers
-               end
-               return self.super_elements_cache[element]
-       end
-
-       # Return all direct super elements of an element
-       redef fun is_element_mi(element) do
-               return self.super_elements(element).length > 1
-       end
-
-       # Return all sub elements (directs and indirects) of an element
-       redef fun sub_elements(element) do
-               if not self.sub_elements_cache.has_key(element) then
-                       var subs = new HashSet[T]
-                       for mtype in self.mtypes do
-                               if element == mtype then continue
-                               if mtype.is_subtype(self.mmodule, null, element) then
-                                       subs.add(mtype)
-                               end
-                       end
-                       self.sub_elements_cache[element] = subs
-               end
-               return self.sub_elements_cache[element]
-       end
+       redef fun super_elements(element) do return self.mmodule.super_mtypes(element, mtypes)
+       redef fun is_element_mi(element) do return self.super_elements(element).length > 1
+       redef fun sub_elements(element) do do return self.mmodule.sub_mtypes(element, mtypes)
+       redef fun linearize(elements) do return self.mmodule.linearize_mtypes(elements)
+       redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mtypes(elements)
 end
 
 class NaiveTypeColoring
@@ -349,40 +287,6 @@ class TypeAndPerfectHashing
        redef fun op(mask, id) do return mask.bin_and(id)
 end
 
-# A sorter for linearize list of types
-class TypeSorter
-       super AbstractSorter[MType]
-
-       private var mmodule: MModule
-
-       init(mmodule: MModule) do self.mmodule = mmodule
-
-       redef fun compare(a, b) do
-               if a == b then
-                       return 0
-               else if a.is_subtype(self.mmodule, null, b) then
-                       return -1
-               end
-               return 1
-       end
-end
-
-# A sorter for reverse linearization
-class ReverseTypeSorter
-       super TypeSorter
-
-       init(mmodule: MModule) do end
-
-       redef fun compare(a, b) do
-               if a == b then
-                       return 0
-               else if a.is_subtype(self.mmodule, null, b) then
-                       return 1
-               end
-               return -1
-       end
-end
-
 # MClass coloring
 class ClassColoring
        super AbstractColoring[MClass]
@@ -396,10 +300,7 @@ class ClassColoring
        private var parent_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
        private var sub_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
 
-       init(mainmodule: MModule) do
-               super(new ClassSorter(mainmodule), new ReverseClassSorter(mainmodule))
-               self.mmodule = mainmodule
-       end
+       init(mainmodule: MModule) do self.mmodule = mainmodule
 
        # Build type tables
        fun build_type_tables(mclasses: Array[T], colors: Map[T, Int]): Map[T, Array[nullable T]] do
@@ -424,53 +325,12 @@ class ClassColoring
                return tables
        end
 
-       redef fun super_elements(element) do
-               if not self.super_elements_cache.has_key(element) then
-                       var supers = new HashSet[T]
-                       if self.mmodule.flatten_mclass_hierarchy.has(element) then
-                               for sup in self.mmodule.flatten_mclass_hierarchy[element].greaters do
-                                       if element == sup then continue
-                                       supers.add(sup)
-                               end
-                       end
-                       self.super_elements_cache[element] = supers
-               end
-               return self.super_elements_cache[element]
-       end
-
-       private fun parent_elements(element: T): Set[T] do
-               if not self.parent_elements_cache.has_key(element) then
-                       var parents = new HashSet[T]
-                       if self.mmodule.flatten_mclass_hierarchy.has(element) then
-                               for parent in self.mmodule.flatten_mclass_hierarchy[element].direct_greaters do
-                                       if element == parent then continue
-                                       parents.add(parent)
-                               end
-                       end
-                       self.parent_elements_cache[element] = parents
-               end
-               return self.parent_elements_cache[element]
-       end
-
-       # Return all sub elements (directs and indirects) of an element
-       redef fun sub_elements(element) do
-               if not self.sub_elements_cache.has_key(element) then
-                       var subs = new HashSet[T]
-                       if self.mmodule.flatten_mclass_hierarchy.has(element) then
-                               for sub in self.mmodule.flatten_mclass_hierarchy[element].smallers do
-                                       subs.add(sub)
-                               end
-                       end
-                       self.sub_elements_cache[element] = subs
-               end
-               return self.sub_elements_cache[element]
-       end
-
-       # Return all direct super elements of an element
-       redef fun is_element_mi(element) do
-               if not self.mmodule.flatten_mclass_hierarchy.has(element) then return false
-               return self.mmodule.flatten_mclass_hierarchy[element].direct_greaters.length > 1
-       end
+       redef fun super_elements(element) do return self.mmodule.super_mclasses(element)
+       fun parent_elements(element: MClass): Set[MClass] do return self.mmodule.parent_mclasses(element)
+       redef fun is_element_mi(element) do return self.parent_elements(element).length > 1
+       redef fun sub_elements(element) do do return self.mmodule.sub_mclasses(element)
+       redef fun linearize(elements) do return self.mmodule.linearize_mclasses(elements)
+       redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mclasses(elements)
 end
 
 # incremental coloring (very naive)
@@ -482,7 +342,7 @@ class NaiveClassColoring
        end
 
        # naive coloring that use incremental coloring
-       redef fun colorize_elements(elements: Collection[MClass]) do
+       redef fun colorize_elements(elements) do
                for e in elements do
                        self.coloration_result[e] = self.coloration_result.length
                end
@@ -570,38 +430,6 @@ class ClassAndPerfectHashing
        redef fun op(mask, id) do return mask.bin_and(id)
 end
 
-# A sorter for linearize list of classes
-private class ClassSorter
-       super AbstractSorter[MClass]
-
-       var mmodule: MModule
-
-       redef fun compare(a, b) do
-               if a == b then
-                       return 0
-               else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
-                       return -1
-               end
-               return 1
-       end
-end
-
-# A sorter for reverse linearization
-private class ReverseClassSorter
-       super AbstractSorter[MClass]
-
-       var mmodule: MModule
-
-       redef fun compare(a, b) do
-               if a == b then
-                       return 0
-               else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
-                       return 1
-               end
-               return -1
-       end
-end
-
 # MProperty coloring
 class PropertyColoring
 
@@ -627,10 +455,9 @@ class PropertyColoring
                for mclass in self.class_coloring.coloration_result.keys do
                        var table = new Array[nullable MPROPDEF]
                        # first, fill table from parents by reverse linearization order
-                       var parents = new OrderedSet[MClass]
-                       parents.add_all(self.class_coloring.super_elements(mclass))
-                       self.class_coloring.reverse_sorter.sort(parents)
-                       for parent in parents do
+                       var parents = self.class_coloring.super_elements(mclass)
+                       var lin = self.class_coloring.reverse_linearize(parents)
+                       for parent in lin do
                                for mproperty in self.properties(parent) do
                                        var color = self.coloration_result[mproperty]
                                        if table.length <= color then
@@ -848,10 +675,9 @@ abstract class VTPerfectHashing
                for mclass in self.class_coloring.coloration_result.keys do
                        var table = new Array[nullable MPROPDEF]
                        # first, fill table from parents by reverse linearization order
-                       var parents = new OrderedSet[MClass]
-                       parents.add_all(self.class_coloring.super_elements(mclass))
-                       self.class_coloring.reverse_sorter.sort(parents)
-                       for parent in parents do
+                       var parents = self.class_coloring.super_elements(mclass)
+                       var lin = self.class_coloring.reverse_linearize(parents)
+                       for parent in lin do
                                for mproperty in self.properties(parent) do
                                        var color = phash(self.coloration_result[mproperty], masks[mclass])
                                        if table.length <= color then
@@ -1318,24 +1144,24 @@ end
 # live unanchored coloring
 class UnanchoredTypeColoring
 
-       private var coloration_result: Map[MClassType, Int] = new HashMap[MClassType, Int]
-       private var conflicts_graph: Map[MClassType, Set[MClassType]] = new HashMap[MClassType, Set[MClassType]]
+       private var coloration_result: Map[MType, Int] = new HashMap[MType, Int]
+       private var conflicts_graph: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
 
        init do end
 
-       fun colorize(elements: Map[MClassType, Set[MClassType]]): Map[MClassType, Int] do
+       fun colorize(elements: Map[MClassType, Set[MType]]): Map[MType, Int] do
                build_conflicts_graph(elements)
                colorize_elements(elements)
                return coloration_result
        end
 
-       fun build_tables(elements: Map[MClassType, Set[MClassType]]): Map[MClassType, Array[nullable MClassType]] do
-               var tables = new HashMap[MClassType, Array[nullable MClassType]]
+       fun build_tables(elements: Map[MClassType, Set[MType]]): Map[MClassType, Array[nullable MType]] do
+               var tables = new HashMap[MClassType, Array[nullable MType]]
 
                for mclasstype, mtypes in elements do
-                       var table = new Array[nullable MClassType]
+                       var table = new Array[nullable MType]
                        for mtype in mtypes do
-                               var color = self.coloration_result[mtype.mclass.mclass_type]
+                               var color = self.coloration_result[mtype]
                                if table.length <= color then
                                        for i in [table.length .. color[ do
                                                table[i] = null
@@ -1349,23 +1175,23 @@ class UnanchoredTypeColoring
        end
 
        # Colorize a collection of elements
-       fun colorize_elements(elements: Map[MClassType, Set[MClassType]]) do
+       fun colorize_elements(elements: Map[MClassType, Set[MType]]) do
                var min_color = 0
                for mclasstype, mclasstypes in elements do
                        for element in mclasstypes do
-                               if self.coloration_result.has_key(element.mclass.mclass_type) then continue
+                               if self.coloration_result.has_key(element) then continue
                                var color = min_color
-                               while not self.is_color_free(element.mclass.mclass_type, color) do
+                               while not self.is_color_free(element, color) do
                                        color += 1
                                end
-                               coloration_result[element.mclass.mclass_type] = color
+                               coloration_result[element] = color
                                color = min_color
                        end
                end
        end
 
        # Check if a related element to the element already use the color
-       private fun is_color_free(element: MClassType, color: Int): Bool do
+       private fun is_color_free(element: MType, color: Int): Bool do
                if conflicts_graph.has_key(element) then
                        for st in conflicts_graph[element] do
                                if coloration_result.has_key(st) and coloration_result[st] == color then return false
@@ -1375,22 +1201,22 @@ class UnanchoredTypeColoring
        end
 
        # look for unanchored types generated by the same type
-       private fun build_conflicts_graph(elements: Map[MClassType, Set[MClassType]]) do
+       private fun build_conflicts_graph(elements: Map[MClassType, Set[MType]]) do
                for mclasstype, mtypes in elements do
                        for mtype in mtypes do
                                for otype in mtypes do
                                        if otype == mtype then continue
-                                       self.add_conflict(mtype.mclass.mclass_type, otype.mclass.mclass_type)
+                                       self.add_conflict(mtype, otype)
                                end
                        end
                end
        end
 
-       private fun add_conflict(mtype: MClassType, otype: MClassType) do
+       private fun add_conflict(mtype: MType, otype: MType) do
                if mtype == otype then return
-               if not self.conflicts_graph.has_key(mtype) then  self.conflicts_graph[mtype] = new HashSet[MClassType]
+               if not self.conflicts_graph.has_key(mtype) then  self.conflicts_graph[mtype] = new HashSet[MType]
                self.conflicts_graph[mtype].add(otype)
-               if not self.conflicts_graph.has_key(otype) then  self.conflicts_graph[otype] = new HashSet[MClassType]
+               if not self.conflicts_graph.has_key(otype) then  self.conflicts_graph[otype] = new HashSet[MType]
                self.conflicts_graph[otype].add(mtype)
        end
 end
@@ -1400,11 +1226,11 @@ class NaiveUnanchoredTypeColoring
 
        init do end
 
-       redef fun colorize_elements(elements: Map[MClassType, Set[MClassType]]) do
+       redef fun colorize_elements(elements: Map[MClassType, Set[MType]]) do
                var color = 0
                for mclasstype, mclasstypes in elements do
                        for element in mclasstypes do
-                               coloration_result[element.mclass.mclass_type] = color
+                               coloration_result[element] = color
                                color += 1
                        end
                end
@@ -1418,29 +1244,29 @@ abstract class UnanchoredTypePerfectHashing
 
        init do end
 
-       redef fun colorize_elements(elements: Map[MClassType, Set[MClassType]]) do
+       redef fun colorize_elements(elements: Map[MClassType, Set[MType]]) do
                var color = 1
                for mclasstype, mclasstypes in elements do
                        for element in mclasstypes do
-                               coloration_result[element.mclass.mclass_type] = color
+                               coloration_result[element] = color
                                color += 1
                        end
                end
        end
 
-       fun compute_masks(elements: Map[MClassType, Set[MClassType]]): Map[MClassType, Int] do
+       fun compute_masks(elements: Map[MClassType, Set[MType]]): Map[MClassType, Int] do
                for mclasstype, mtypes in elements do
                        self.masks[mclasstype] = compute_mask(mtypes)
                end
                return self.masks
        end
 
-       private fun compute_mask(mtypes: Set[MClassType]): Int do
+       private fun compute_mask(mtypes: Set[MType]): Int do
                var mask = 0
                loop
                        var used = new List[Int]
                        for mtype in mtypes do
-                               var res = op(mask, self.coloration_result[mtype.mclass.mclass_type])
+                               var res = op(mask, self.coloration_result[mtype])
                                if used.has(res) then
                                        break
                                else
@@ -1453,13 +1279,13 @@ abstract class UnanchoredTypePerfectHashing
                return mask
        end
 
-       redef fun build_tables(elements: Map[MClassType, Set[MClassType]]): Map[MClassType, Array[nullable MClassType]] do
-               var tables = new HashMap[MClassType, Array[nullable MClassType]]
+       redef fun build_tables(elements: Map[MClassType, Set[MType]]): Map[MClassType, Array[nullable MType]] do
+               var tables = new HashMap[MClassType, Array[nullable MType]]
 
                for mclasstype, mtypes in elements do
-                       var table = new Array[nullable MClassType]
+                       var table = new Array[nullable MType]
                        for mtype in mtypes do
-                               var color = phash(self.coloration_result[mtype.mclass.mclass_type], masks[mclasstype])
+                               var color = phash(self.coloration_result[mtype], masks[mclasstype])
                                if table.length <= color then
                                        for i in [table.length .. color[ do
                                                table[i] = null
@@ -1491,31 +1317,230 @@ end
 
 # Utils
 
-# An ordered set
-class OrderedSet[E: Object]
-       super Array[E]
-
-       init do end
-
-       init from(elements: Set[E]) do
+redef class HashSet[E]
+       init from(elements: Collection[E]) do
+               init
                self.add_all(elements)
        end
+end
 
-       redef fun add(e) do
-               if not self.has(e) then
-                       super(e)
-               end
+redef class Array[E]
+       init from(elements: Collection[E]) do
+               init
+               self.add_all(elements)
        end
 
-       # Return a new OrderedSet with the elements only contened in 'self' and not in 'o'
-       fun -(o: OrderedSet[E]): OrderedSet[E] do
-               var res = new OrderedSet[E]
+       # Return a new Array with the elements only contened in 'self' and not in 'o'
+       fun -(o: Array[E]): Array[E] do
+               var res = new Array[E]
                for e in self do if not o.has(e) then res.add(e)
                return res
        end
+end
+
+redef class MModule
+
+       # Return a linearization of a set of mtypes
+       private fun linearize_mtypes(mtypes: Set[MType]): Array[MType] do
+               var lin = new Array[MType].from(mtypes)
+               var sorter = new TypeSorter(self)
+               sorter.sort(lin)
+               return lin
+       end
+
+       # Return a reverse linearization of a set of mtypes
+       private fun reverse_linearize_mtypes(mtypes: Set[MType]): Array[MType] do
+               var lin = new Array[MType].from(mtypes)
+               var sorter = new ReverseTypeSorter(self)
+               sorter.sort(lin)
+               return lin
+       end
+
+       # Return super types of a `mtype` in `self`
+       private fun super_mtypes(mtype: MType, mtypes: Set[MType]): Set[MType] do
+               if not self.super_mtypes_cache.has_key(mtype) then
+                       var supers = new HashSet[MType]
+                       for otype in mtypes do
+                               if otype == mtype then continue
+                               if mtype.is_subtype(self, null, otype) then
+                                       supers.add(otype)
+                               end
+                       end
+                       self.super_mtypes_cache[mtype] = supers
+               end
+               return self.super_mtypes_cache[mtype]
+       end
+
+       private var super_mtypes_cache: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
+
+       # Return all sub mtypes (directs and indirects) of a `mtype` in `self`
+       private fun sub_mtypes(mtype: MType, mtypes: Set[MType]): Set[MType] do
+               if not self.sub_mtypes_cache.has_key(mtype) then
+                       var subs = new HashSet[MType]
+                       for otype in mtypes do
+                               if otype == mtype then continue
+                               if otype.is_subtype(self, null, mtype) then
+                                       subs.add(otype)
+                               end
+                       end
+                       self.sub_mtypes_cache[mtype] = subs
+               end
+               return self.sub_mtypes_cache[mtype]
+       end
+
+       private var sub_mtypes_cache: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
+
+       # Return a linearization of a set of mclasses
+       private fun linearize_mclasses(mclasses: Set[MClass]): Array[MClass] do
+               var lin = new Array[MClass].from(mclasses)
+               var sorter = new ClassSorter(self)
+               sorter.sort(lin)
+               return lin
+       end
+
+       # Return a reverse linearization of a set of mtypes
+       private fun reverse_linearize_mclasses(mclasses: Set[MClass]): Array[MClass] do
+               var lin = new Array[MClass].from(mclasses)
+               var sorter = new ReverseClassSorter(self)
+               sorter.sort(lin)
+               return lin
+       end
+
+       # Return all super mclasses (directs and indirects) of a `mclass` in `self`
+       private fun super_mclasses(mclass: MClass): Set[MClass] do
+               if not self.super_mclasses_cache.has_key(mclass) then
+                       var supers = new HashSet[MClass]
+                       if self.flatten_mclass_hierarchy.has(mclass) then
+                               for sup in self.flatten_mclass_hierarchy[mclass].greaters do
+                                       if sup == mclass then continue
+                                       supers.add(sup)
+                               end
+                       end
+                       self.super_mclasses_cache[mclass] = supers
+               end
+               return self.super_mclasses_cache[mclass]
+       end
+
+       private var super_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
+
+       # Return all parents of a `mclass` in `self`
+       private fun parent_mclasses(mclass: MClass): Set[MClass] do
+               if not self.parent_mclasses_cache.has_key(mclass) then
+                       var parents = new HashSet[MClass]
+                       if self.flatten_mclass_hierarchy.has(mclass) then
+                               for sup in self.flatten_mclass_hierarchy[mclass].direct_greaters do
+                                       if sup == mclass then continue
+                                       parents.add(sup)
+                               end
+                       end
+                       self.parent_mclasses_cache[mclass] = parents
+               end
+               return self.parent_mclasses_cache[mclass]
+       end
+
+       private var parent_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
+
+       # Return all sub mclasses (directs and indirects) of a `mclass` in `self`
+       private fun sub_mclasses(mclass: MClass): Set[MClass] do
+               if not self.sub_mclasses_cache.has_key(mclass) then
+                       var subs = new HashSet[MClass]
+                       if self.flatten_mclass_hierarchy.has(mclass) then
+                               for sub in self.flatten_mclass_hierarchy[mclass].smallers do
+                                       if sub == mclass then continue
+                                       subs.add(sub)
+                               end
+                       end
+                       self.sub_mclasses_cache[mclass] = subs
+               end
+               return self.sub_mclasses_cache[mclass]
+       end
+
+       private var sub_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
+
+       # All 'mproperties' associated to all 'mclassdefs' of `mclass`
+       private fun properties(mclass: MClass): Set[MProperty] do
+               if not self.properties_cache.has_key(mclass) then
+                       var properties = new HashSet[MProperty]
+                       var parents = self.super_mclasses(mclass)
+                       for parent in parents do
+                               properties.add_all(self.properties(parent))
+                       end
+
+                       for mclassdef in mclass.mclassdefs do
+                               for mpropdef in mclassdef.mpropdefs do
+                                       properties.add(mpropdef.mproperty)
+                               end
+                       end
+                       self.properties_cache[mclass] = properties
+               end
+               return properties_cache[mclass]
+       end
 
-       # Linearize a set of elements
-       fun linearize(sorter: AbstractSorter[E]) do
-               sorter.sort(self)
+       private var properties_cache: Map[MClass, Set[MProperty]] = new HashMap[MClass, Set[MProperty]]
+end
+
+# A sorter for linearize list of types
+class TypeSorter
+       super AbstractSorter[MType]
+
+       private var mmodule: MModule
+
+       init(mmodule: MModule) do self.mmodule = mmodule
+
+       redef fun compare(a, b) do
+               if a == b then
+                       return 0
+               else if a.is_subtype(self.mmodule, null, b) then
+                       return -1
+               end
+               return 1
+       end
+end
+
+# A sorter for reverse linearization
+class ReverseTypeSorter
+       super TypeSorter
+
+       init(mmodule: MModule) do end
+
+       redef fun compare(a, b) do
+               if a == b then
+                       return 0
+               else if a.is_subtype(self.mmodule, null, b) then
+                       return 1
+               end
+               return -1
        end
-end
\ No newline at end of file
+end
+
+# A sorter for linearize list of classes
+private class ClassSorter
+       super AbstractSorter[MClass]
+
+       var mmodule: MModule
+
+       redef fun compare(a, b) do
+               if a == b then
+                       return 0
+               else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
+                       return -1
+               end
+               return 1
+       end
+end
+
+# A sorter for reverse linearization
+private class ReverseClassSorter
+       super AbstractSorter[MClass]
+
+       var mmodule: MModule
+
+       redef fun compare(a, b) do
+               if a == b then
+                       return 0
+               else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
+                       return 1
+               end
+               return -1
+       end
+end