nitg-sep: move struct instances declarations to header file
[nit.git] / src / coloring.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Graph coloring tools
16 module coloring
17
18 import rapid_type_analysis # for type coloration
19
20 abstract class AbstractColoring[E: Object]
21
22 private var sorter: AbstractSorter[E]
23 private var reverse_sorter: AbstractSorter[E]
24
25 private var core: OrderedSet[E] = new OrderedSet[E]
26 private var crown: OrderedSet[E] = new OrderedSet[E]
27 private var border: OrderedSet[E] = new OrderedSet[E]
28
29 private var coloration_result: Map[E, Int] = new HashMap[E, Int]
30 private var conflicts_graph_cache: nullable HashMap[E, Set[E]]
31
32 init(sorter: AbstractSorter[E], reverse_sorter: AbstractSorter[E]) do
33 self.sorter = sorter
34 self.reverse_sorter = reverse_sorter
35 end
36
37 fun colorize(elements: Collection[E]): Map[E, Int] do
38 # tag each element as part of group core, crown or border
39 for e in elements do
40 tag_element(e)
41 end
42
43 #print "core: {core.join(", ")}"
44 #print "border: {border.join(", ")}"
45 #print "crown: {crown.join(", ")}"
46
47 # sort by reverse linearization order
48 reverse_sorter.sort(core)
49 reverse_sorter.sort(border)
50 reverse_sorter.sort(crown)
51
52 #print "conflicts"
53 #for k, v in conflicts_graph do
54 # if k isa MType then
55 # print "{k}: {v.join(", ")}"
56 # end
57 #end
58
59 # colorize graph
60 colorize_elements(core)
61 colorize_elements(border)
62 colorize_elements(crown)
63
64 return coloration_result
65 end
66
67 # Colorize a collection of elements
68 private fun colorize_elements(elements: Collection[E]) do
69 var min_color = 0
70
71 for element in elements do
72 var color = min_color
73 while not self.is_color_free(element, color) do
74 color += 1
75 end
76 coloration_result[element] = color
77 color = min_color
78 end
79 end
80
81 # Check if a related element to the element already use the color
82 private fun is_color_free(element: E, color: Int): Bool do
83 if conflicts_graph.has_key(element) then
84 for st in conflicts_graph[element] do
85 if coloration_result.has_key(st) and coloration_result[st] == color then return false
86 end
87 end
88 for st in self.super_elements(element) do
89 if coloration_result.has_key(st) and coloration_result[st] == color then return false
90 end
91 return true
92 end
93
94 # Tag element as core, crown or border
95 private fun tag_element(element: E) do
96 # Check if sub elements are all in single inheritance
97 var all_subelements_si = true
98 for subelem in self.sub_elements(element) do
99 if self.is_element_mi(subelem) then
100 all_subelements_si = false
101 break
102 end
103 end
104
105 # Tag as core, crown or border
106 if self.is_element_mi(element) then
107 core.add_all(self.super_elements(element))
108 core.add(element)
109 if all_subelements_si then
110 border.add(element)
111 end
112 else if not all_subelements_si then
113 core.add_all(self.super_elements(element))
114 core.add(element)
115 else
116 crown.add(element)
117 end
118 end
119
120 # Conflicts graph of elements hierarchy (two types are in conflict if they have common subelements)
121 private fun conflicts_graph: Map[E, Set[E]] do
122 if self.conflicts_graph_cache == null then
123 self.conflicts_graph_cache = new HashMap[E, HashSet[E]]
124 for t in self.core do
125 for i in self.linear_extension(t) do
126 if t == i then continue
127
128 var lin_i = self.linear_extension(i)
129
130 for j in self.linear_extension(t) do
131 if i == j or j == t then continue
132 var lin_j = self.linear_extension(j)
133
134 var d_ij = lin_i - lin_j
135 var d_ji = lin_j - lin_i
136
137 for ed1 in d_ij do
138 if not conflicts_graph_cache.has_key(ed1) then conflicts_graph_cache[ed1] = new HashSet[E]
139 # add ed1 x ed2 to conflicts graph
140 for ed2 in d_ji do conflicts_graph_cache[ed1].add(ed2)
141 end
142 for ed1 in d_ij do
143 if not conflicts_graph_cache.has_key(ed1) then conflicts_graph_cache[ed1] = new HashSet[E]
144 # add ed1 x ed2 to conflicts graph
145 for ed2 in d_ji do conflicts_graph_cache[ed1].add(ed2)
146 end
147 end
148 end
149 end
150 end
151 return conflicts_graph_cache.as(not null)
152 end
153
154 # cache for linear_extensions
155 private var linear_extensions_cache: Map[E, OrderedSet[E]] = new HashMap[E, OrderedSet[E]]
156
157 # Return a linear_extension of super_elements of the element
158 private fun linear_extension(element: E): OrderedSet[E] do
159 if not self.linear_extensions_cache.has_key(element) then
160 var lin = new OrderedSet[E]
161 lin.add(element)
162 lin.add_all(self.super_elements(element))
163 self.sorter.sort(lin)
164 self.linear_extensions_cache[element] = lin
165 end
166 return self.linear_extensions_cache[element]
167 end
168
169 # Return all super elements (directs and indirects) of an element
170 private fun super_elements(element: E): Collection[E] is abstract
171
172 # Return all sub elements (directs and indirects) of an element
173 private fun sub_elements(element: E): Collection[E] is abstract
174
175 # Is the element in multiple inheritance ?
176 private fun is_element_mi(element: E): Bool is abstract
177 end
178
179 # MClassType coloring
180 class TypeColoring
181 super AbstractColoring[MClassType]
182
183 type T: MClassType
184
185 private var mmodule: MModule
186 private var mtypes: Set[MClassType] = new HashSet[MClassType]
187
188 # caches
189 private var super_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
190 private var sub_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
191
192 init(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis) do
193 super(new TypeSorter(mainmodule), new ReverseTypeSorter(mainmodule))
194 self.mmodule = mainmodule
195 self.mtypes.add_all(runtime_type_analysis.live_types)
196 self.mtypes.add_all(runtime_type_analysis.live_cast_types)
197 end
198
199 # Build type tables
200 private fun build_type_tables(mtypes: Set[T], colors: Map[T, Int]): Map[T, Array[nullable T]] do
201 var tables = new HashMap[T, Array[nullable T]]
202
203 for mtype in mtypes do
204 var table = new Array[nullable T]
205 var supers = new HashSet[T]
206 supers.add_all(self.super_elements(mtype))
207 supers.add(mtype)
208 for sup in supers do
209 var color = colors[sup]
210 if table.length <= color then
211 for i in [table.length .. color[ do
212 table[i] = null
213 end
214 end
215 table[color] = sup
216 end
217 tables[mtype] = table
218 end
219 return tables
220 end
221
222 redef fun super_elements(element) do
223 if not self.super_elements_cache.has_key(element) then
224 var supers = new HashSet[T]
225 for mtype in self.mtypes do
226 if element == mtype then continue
227 if element.is_subtype(self.mmodule, null, mtype) then
228 supers.add(mtype)
229 end
230 end
231 self.super_elements_cache[element] = supers
232 end
233 return self.super_elements_cache[element]
234 end
235
236 # Return all direct super elements of an element
237 redef fun is_element_mi(element) do
238 return self.mmodule.flatten_mclass_hierarchy[element.mclass].direct_greaters.length > 1
239 end
240
241 # Return all sub elements (directs and indirects) of an element
242 redef fun sub_elements(element) do
243 if not self.sub_elements_cache.has_key(element) then
244 var subs = new HashSet[T]
245 for mtype in self.mtypes do
246 if element == mtype then continue
247 if mtype.is_subtype(self.mmodule, null, element) then
248 subs.add(mtype)
249 end
250 end
251 self.sub_elements_cache[element] = subs
252 end
253 return self.sub_elements_cache[element]
254 end
255 end
256
257 # A sorter for linearize list of types
258 private class TypeSorter
259 super AbstractSorter[MClassType]
260
261 private var mmodule: MModule
262
263 init(mmodule: MModule) do self.mmodule = mmodule
264
265 redef fun compare(a, b) do
266 if a == b then
267 return 0
268 else if a.is_subtype(self.mmodule, null, b) then
269 return -1
270 end
271 return 1
272 end
273 end
274
275 # A sorter for reverse linearization
276 private class ReverseTypeSorter
277 super TypeSorter
278
279 redef fun compare(a, b) do
280 if a == b then
281 return 0
282 else if a.is_subtype(self.mmodule, null, b) then
283 return 1
284 end
285 return -1
286 end
287 end
288
289 # MClass coloring
290 class ClassColoring
291 super AbstractColoring[MClass]
292
293 type T: MClass
294
295 private var mmodule: MModule
296
297 # caches
298 private var super_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
299 private var parent_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
300 private var sub_elements_cache: Map[T, Set[T]] = new HashMap[T, Set[T]]
301
302 init(mainmodule: MModule) do
303 super(new ClassSorter(mainmodule), new ReverseClassSorter(mainmodule))
304 self.mmodule = mainmodule
305 end
306
307 redef fun super_elements(element) do
308 if not self.super_elements_cache.has_key(element) then
309 var supers = new HashSet[T]
310 for sup in self.mmodule.flatten_mclass_hierarchy[element].greaters do
311 if element == sup then continue
312 supers.add(sup)
313 end
314 self.super_elements_cache[element] = supers
315 end
316 return self.super_elements_cache[element]
317 end
318
319 private fun parent_elements(element: T): Set[T] do
320 if not self.parent_elements_cache.has_key(element) then
321 var parents = new HashSet[T]
322 for parent in self.mmodule.flatten_mclass_hierarchy[element].direct_greaters do
323 if element == parent then continue
324 parents.add(parent)
325 end
326 self.parent_elements_cache[element] = parents
327 end
328 return self.parent_elements_cache[element]
329 end
330
331 # Return all sub elements (directs and indirects) of an element
332 redef fun sub_elements(element) do
333 if not self.sub_elements_cache.has_key(element) then
334 var subs = new HashSet[T]
335 for sub in self.mmodule.flatten_mclass_hierarchy[element].smallers do
336 subs.add(sub)
337 end
338 self.sub_elements_cache[element] = subs
339 end
340 return self.sub_elements_cache[element]
341 end
342
343 # Return all direct super elements of an element
344 redef fun is_element_mi(element) do
345 return self.mmodule.flatten_mclass_hierarchy[element].direct_greaters.length > 1
346 end
347 end
348
349 # A sorter for linearize list of classes
350 private class ClassSorter
351 super AbstractSorter[MClass]
352
353 var mmodule: MModule
354
355 redef fun compare(a, b) do
356 if a == b then
357 return 0
358 else if self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
359 return -1
360 end
361 return 1
362 end
363 end
364
365 # A sorter for reverse linearization
366 private class ReverseClassSorter
367 super AbstractSorter[MClass]
368
369 var mmodule: MModule
370
371 redef fun compare(a, b) do
372 if a == b then
373 return 0
374 else if self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
375 return 1
376 end
377 return -1
378 end
379 end
380
381 # MProperty coloring
382 class PropertyColoring
383
384 type MPROP: MProperty
385 type MPROPDEF: MPropDef
386
387 private var class_coloring: ClassColoring
388 private var coloration_result: Map[MPROP, Int] = new HashMap[MPROP, Int]
389
390 init(class_coloring: ClassColoring) do
391 self.class_coloring = class_coloring
392 end
393
394 private fun colorize: Map[MPROP, Int] do
395 colorize_core_properties
396 colorize_crown_properties
397 return self.coloration_result
398 end
399
400 private fun build_property_tables: Map[MClass, Array[nullable MPROPDEF]] do
401 var tables = new HashMap[MClass, Array[nullable MPROPDEF]]
402
403 for mclass in self.class_coloring.coloration_result.keys do
404 var table = new Array[nullable MPROPDEF]
405 # first, fill table from parents by reverse linearization order
406 var parents = new OrderedSet[MClass]
407 parents.add_all(self.class_coloring.super_elements(mclass))
408 self.class_coloring.reverse_sorter.sort(parents)
409 for parent in parents do
410 for mproperty in self.properties(parent) do
411 var color = self.coloration_result[mproperty]
412 if table.length <= color then
413 for i in [table.length .. color[ do
414 table[i] = null
415 end
416 end
417 for mpropdef in mproperty.mpropdefs do
418 if mpropdef.mclassdef.mclass == parent then
419 table[color] = mpropdef
420 end
421 end
422 end
423 end
424
425 # then override with local properties
426 for mproperty in self.properties(mclass) do
427 var color = self.coloration_result[mproperty]
428 if table.length <= color then
429 for i in [table.length .. color[ do
430 table[i] = null
431 end
432 end
433 for mpropdef in mproperty.mpropdefs do
434 if mpropdef.mclassdef.mclass == mclass then
435 table[color] = mpropdef
436 end
437 end
438 end
439 tables[mclass] = table
440 end
441 return tables
442 end
443
444 # Colorize properties of the core hierarchy
445 private fun colorize_core_properties do
446 var mclasses = self.class_coloring.core
447 var min_color = 0
448
449 for mclass in mclasses do
450 var color = min_color
451
452 # if the class is root, get the minimal color
453 if self.class_coloring.parent_elements(mclass).length == 0 then
454 colorize_elements(self.properties(mclass), color)
455 else
456 # check last color used by parents
457 color = max_color(color, self.class_coloring.parent_elements(mclass))
458 # check max color used in conflicts
459 if self.class_coloring.conflicts_graph.has_key(mclass) then
460 color = max_color(color, self.class_coloring.conflicts_graph[mclass])
461 end
462
463 # colorize
464 colorize_elements(self.properties(mclass), color)
465 end
466 end
467 end
468
469 # Colorize properties of the crown hierarchy
470 private fun colorize_crown_properties do
471 for mclass in self.class_coloring.crown do
472 colorize_elements(self.properties(mclass), max_color(0, self.class_coloring.parent_elements(mclass)))
473 end
474 end
475
476 # Colorize a collection of properties given a starting color
477 private fun colorize_elements(elements: Collection[MPROP], start_color: Int) do
478 for element in elements do
479 if self.coloration_result.has_key(element) then continue
480 self.coloration_result[element] = start_color
481 start_color += 1
482 end
483 end
484
485 private fun max_color(min_color: Int, mclasses: Collection[MClass]): Int do
486 var max_color = min_color
487
488 for mclass in mclasses do
489 for mproperty in self.properties(mclass) do
490 var color = min_color
491 if self.coloration_result.has_key(mproperty) then
492 color = self.coloration_result[mproperty]
493 if color >= max_color then max_color = color + 1
494 end
495 end
496 end
497 return max_color
498 end
499
500 # properties cache
501 private var properties_cache: Map[MClass, Set[MPROP]] = new HashMap[MClass, Set[MPROP]]
502
503 # All 'mproperties' associated to all 'mclassdefs' of the class
504 private fun properties(mclass: MClass): Set[MPROP] do
505 if not self.properties_cache.has_key(mclass) then
506 var properties = new HashSet[MPROP]
507 var parents = self.class_coloring.super_elements(mclass)
508 for parent in parents do
509 properties.add_all(self.properties(parent))
510 end
511
512 for mclassdef in mclass.mclassdefs do
513 for mpropdef in mclassdef.mpropdefs do
514 var mproperty = mpropdef.mproperty
515 if mproperty isa MPROP then
516 properties.add(mproperty)
517 end
518 end
519 end
520 self.properties_cache[mclass] = properties
521 end
522 return properties_cache[mclass]
523 end
524 end
525
526 # MMethod coloring
527 class MethodColoring
528 super PropertyColoring
529
530 redef type MPROP: MMethod
531 redef type MPROPDEF: MMethodDef
532 end
533
534 # MAttribute coloring
535 class AttributeColoring
536 super PropertyColoring
537
538 redef type MPROP: MAttribute
539 redef type MPROPDEF: MAttributeDef
540 end
541
542 # MParameterType coloring
543 class FTColoring
544 private var class_coloring: ClassColoring
545 private var coloration_result: Map[MParameterType, Int] = new HashMap[MParameterType, Int]
546
547 init(class_coloring: ClassColoring) do
548 self.class_coloring = class_coloring
549 end
550
551 private fun colorize: Map[MParameterType, Int] do
552 colorize_core_properties
553 colorize_crown_properties
554 return self.coloration_result
555 end
556
557 # Colorize properties of the core hierarchy
558 private fun colorize_core_properties do
559 var mclasses = self.class_coloring.core
560 var min_color = 0
561
562 for mclass in mclasses do
563 var color = min_color
564
565 # if the class is root, get the minimal color
566 if self.class_coloring.parent_elements(mclass).length == 0 then
567 colorize_elements(self.fts(mclass), color)
568 else
569 # check last color used by parents
570 color = max_color(color, self.class_coloring.parent_elements(mclass))
571 # check max color used in conflicts
572 if self.class_coloring.conflicts_graph.has_key(mclass) then
573 color = max_color(color, self.class_coloring.conflicts_graph[mclass])
574 end
575 # colorize
576 colorize_elements(self.fts(mclass), color)
577 end
578 end
579 end
580
581 # Colorize properties of the crown hierarchy
582 private fun colorize_crown_properties do
583 for mclass in self.class_coloring.crown do
584 colorize_elements(self.fts(mclass), max_color(0, self.class_coloring.parent_elements(mclass)))
585 end
586 end
587
588 # Colorize a collection of properties given a starting color
589 private fun colorize_elements(elements: Collection[MParameterType], start_color: Int) do
590 for element in elements do
591 if self.coloration_result.has_key(element) then continue
592 self.coloration_result[element] = start_color
593 start_color += 1
594 end
595 end
596
597 private fun max_color(min_color: Int, mclasses: Collection[MClass]): Int do
598 var max_color = min_color
599
600 for mclass in mclasses do
601 for ft in self.fts(mclass) do
602 var color = min_color
603 if self.coloration_result.has_key(ft) then
604 color = self.coloration_result[ft]
605 if color >= max_color then max_color = color + 1
606 end
607 end
608 end
609 return max_color
610 end
611
612 # fts cache
613 private var fts_cache: Map[MClass, Set[MParameterType]] = new HashMap[MClass, Set[MParameterType]]
614
615 private fun fts(mclass: MClass): Set[MParameterType] do
616 if not self.fts_cache.has_key(mclass) then
617 var fts = new HashSet[MParameterType]
618 var mclass_type = mclass.mclass_type
619 if mclass_type isa MGenericType then
620 for ft in mclass_type.arguments do
621 fts.add(ft.as(MParameterType))
622 end
623 end
624 self.fts_cache[mclass] = fts
625 end
626 return fts_cache[mclass]
627 end
628
629 private fun build_ft_tables: Map[MClass, Array[nullable MParameterType]] do
630 var tables = new HashMap[MClass, Array[nullable MParameterType]]
631
632 for mclass in self.class_coloring.coloration_result.keys do
633 var table = new Array[nullable MParameterType]
634
635 # first, fill table from parents
636 for parent in self.class_coloring.super_elements(mclass) do
637 for ft in self.fts(parent) do
638 var color = self.coloration_result[ft]
639 if table.length <= color then
640 for i in [table.length .. color[ do
641 table[i] = null
642 end
643 end
644 table[color] = ft
645 end
646 end
647
648 # then override with local properties
649 for ft in self.fts(mclass) do
650 var color = self.coloration_result[ft]
651 if table.length <= color then
652 for i in [table.length .. color[ do
653 table[i] = null
654 end
655 end
656 table[color] = ft
657 end
658 tables[mclass] = table
659 end
660 return tables
661 end
662 end
663
664 # Utils
665
666 # An ordered set
667 private class OrderedSet[E]
668 super Array[E]
669
670 redef fun add(e) do
671 if not self.has(e) then
672 super(e)
673 end
674 end
675
676 # Return a new OrderedSet with the elements only contened in 'self' and not in 'o'
677 fun -(o: OrderedSet[E]): OrderedSet[E] do
678 var res = new OrderedSet[E]
679 for e in self do if not o.has(e) then res.add(e)
680 return res
681 end
682 end