40d5e4fe915f5c12db44906e12ae5b756ee129aa
[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 typing
19
20 # Layouts
21
22 class TypingLayout[E]
23 # Unic ids or each element
24 var ids: Map[E, Int] = new HashMap[E, Int]
25 # Fixed positions of each element in all tables
26 var pos: Map[E, Int] = new HashMap[E, Int]
27 end
28
29 class PHTypingLayout[E]
30 super TypingLayout[E]
31 # Masks used by hash function
32 var masks: Map[E, Int] = new HashMap[E, Int]
33 # Positions of each element for each tables
34 var hashes: Map[E, Map[E, Int]] = new HashMap[E, Map[E, Int]]
35 end
36
37 class PropertyLayout[E]
38 # Fixed positions of each element in all tables
39 var pos: Map[E, Int] = new HashMap[E, Int]
40 end
41
42 # Layout for resolution tables
43 class ResolutionLayout
44 # Unic ids for each resolved type
45 var ids: Map[MType, Int] = new HashMap[MType, Int]
46 # Fixed positions of resolved type
47 var pos: Map[MType, Int] = new HashMap[MType, Int]
48 end
49
50 class PHResolutionLayout
51 super ResolutionLayout
52 # Masks associated to each owner of a resolution table
53 var masks: Map[MClassType, Int] = new HashMap[MClassType, Int]
54 # Positions of each resolvec type for resolution tables
55 var hashes: Map[MClassType, Map[MType, Int]] = new HashMap[MClassType, Map[MType, Int]]
56 end
57
58 # Builders
59
60 abstract class TypingLayoutBuilder[E]
61
62 type LAYOUT: TypingLayout[E]
63
64 private var mmodule: MModule
65 init(mmodule: MModule) do self.mmodule = mmodule
66
67 # Compute elements ids and position
68 fun build_layout(elements: Set[E]): LAYOUT is abstract
69
70 # Give each MType a unic id using a descending linearization of the `mtypes` set
71 private fun compute_ids(elements: Set[E]): Map[E, Int] do
72 var ids = new HashMap[E, Int]
73 var lin = self.reverse_linearize(elements)
74 for element in lin do
75 ids[element] = ids.length
76 end
77 return ids
78 end
79
80 private fun reverse_linearize(elements: Set[E]): Array[E] is abstract
81 end
82
83 # Layout builder for MType using Binary Matrix (BM)
84 class BMTypeLayoutBuilder
85 super TypingLayoutBuilder[MType]
86
87 init(mmodule: MModule) do super
88
89 # Compute mtypes ids and position using BM
90 redef fun build_layout(mtypes) do
91 var result = new TypingLayout[MType]
92 result.ids = self.compute_ids(mtypes)
93 result.pos = result.ids
94 return result
95 end
96
97 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mtypes(elements)
98 end
99
100 # Layout builder for MType using Coloring (CL)
101 class CLTypeLayoutBuilder
102 super TypingLayoutBuilder[MType]
103
104 private var colorer: MTypeColorer
105
106 init(mmodule: MModule) do
107 super
108 self.colorer = new MTypeColorer(mmodule)
109 end
110
111 # Compute mtypes ids and position using BM
112 redef fun build_layout(mtypes) do
113 var result = new TypingLayout[MType]
114 result.ids = self.compute_ids(mtypes)
115 result.pos = self.colorer.colorize(mtypes)
116 return result
117 end
118
119 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mtypes(elements)
120 end
121
122 # Layout builder for MType using Perfect Hashing (PH)
123 class PHTypeLayoutBuilder
124 super TypingLayoutBuilder[MType]
125
126 redef type LAYOUT: PHTypingLayout[MType]
127
128 private var hasher: MTypeHasher
129
130 init(mmodule: MModule, operator: PHOperator) do
131 super
132 self.hasher = new MTypeHasher(mmodule, operator)
133 end
134
135 # Compute mtypes ids and position using BM
136 redef fun build_layout(mtypes) do
137 var result = new PHTypingLayout[MType]
138 result.ids = self.compute_ids(mtypes)
139 result.masks = self.hasher.compute_masks(mtypes, result.ids)
140 result.hashes = self.hasher.compute_hashes(mtypes, result.ids, result.masks)
141 return result
142 end
143
144 # Ids start from 1 instead of 0
145 redef fun compute_ids(mtypes) do
146 var ids = new HashMap[MType, Int]
147 var lin = self.mmodule.reverse_linearize_mtypes(mtypes)
148 for mtype in lin do
149 ids[mtype] = ids.length + 1
150 end
151 return ids
152 end
153
154 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mtypes(elements)
155 end
156
157 # Layout builder for MClass using Binary Matrix (BM)
158 class BMClassLayoutBuilder
159 super TypingLayoutBuilder[MClass]
160
161 init(mmodule: MModule) do super
162
163 # Compute mclasses ids and position using BM
164 redef fun build_layout(mclasses) do
165 var result = new TypingLayout[MClass]
166 result.ids = self.compute_ids(mclasses)
167 result.pos = result.ids
168 return result
169 end
170
171 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mclasses(elements)
172 end
173
174 # Layout builder for MClass using Coloring (CL)
175 class CLClassLayoutBuilder
176 super TypingLayoutBuilder[MClass]
177
178 private var colorer: MClassColorer
179
180 init(mmodule: MModule) do
181 super
182 self.colorer = new MClassColorer(mmodule)
183 end
184
185 # Compute mclasses ids and position using BM
186 redef fun build_layout(mclasses) do
187 var result = new TypingLayout[MClass]
188 result.ids = self.compute_ids(mclasses)
189 result.pos = self.colorer.colorize(mclasses)
190 return result
191 end
192
193 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mclasses(elements)
194 end
195
196 # Layout builder for MClass using Perfect Hashing (PH)
197 class PHClassLayoutBuilder
198 super TypingLayoutBuilder[MClass]
199
200 redef type LAYOUT: PHTypingLayout[MClass]
201
202 private var hasher: MClassHasher
203
204 init(mmodule: MModule, operator: PHOperator) do
205 super
206 self.hasher = new MClassHasher(mmodule, operator)
207 end
208
209 # Compute mclasses ids and position using BM
210 redef fun build_layout(mclasses) do
211 var result = new PHTypingLayout[MClass]
212 result.ids = self.compute_ids(mclasses)
213 result.masks = self.hasher.compute_masks(mclasses, result.ids)
214 result.hashes = self.hasher.compute_hashes(mclasses, result.ids, result.masks)
215 return result
216 end
217
218 # Ids start from 1 instead of 0
219 redef fun compute_ids(mclasses) do
220 var ids = new HashMap[MClass, Int]
221 var lin = self.mmodule.reverse_linearize_mclasses(mclasses)
222 for mclass in lin do
223 ids[mclass] = ids.length + 1
224 end
225 return ids
226 end
227
228 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mclasses(elements)
229 end
230
231 abstract class PropertyLayoutBuilder[E: MProperty]
232
233 type LAYOUT: PropertyLayout[E]
234
235 private var mmodule: MModule
236 init(mmodule: MModule) do self.mmodule = mmodule
237
238 # Compute properties ids and position
239 fun build_layout(mclasses: Set[MClass]): LAYOUT is abstract
240 end
241
242 # Layout builder for MProperty using Coloring (CL)
243 class CLPropertyLayoutBuilder[E: MProperty]
244 super PropertyLayoutBuilder[E]
245
246 private var colorer: MPropertyColorer[E]
247
248 init(mmodule: MModule) do
249 super
250 self.colorer = new MPropertyColorer[E](mmodule)
251 end
252
253 # Compute mclasses ids and position using BM
254 redef fun build_layout(mclasses) do
255 var result = new PropertyLayout[E]
256 result.pos = self.colorer.colorize(mclasses)
257 return result
258 end
259 end
260
261 abstract class ResolutionLayoutBuilder
262
263 type LAYOUT: ResolutionLayout
264
265 init do end
266
267 fun build_layout(elements: Map[MClassType, Set[MType]]): LAYOUT is abstract
268
269 fun compute_ids(elements: Map[MClassType, Set[MType]]): Map[MType, Int] do
270 var ids = new HashMap[MType, Int]
271 var color = 0
272 for mclasstype, mclasstypes in elements do
273 for element in mclasstypes do
274 if ids.has_key(element) then continue
275 ids[element] = color
276 color += 1
277 end
278 end
279 return ids
280 end
281 end
282
283 # Layout builder for MClass using Binary Matrix (BM)
284 class BMResolutionLayoutBuilder
285 super ResolutionLayoutBuilder
286
287 init do super
288
289 # Compute resolved types position using BM
290 redef fun build_layout(elements) do
291 var result = new ResolutionLayout
292 result.ids = self.compute_ids(elements)
293 result.pos = result.ids
294 return result
295 end
296 end
297
298 # Layout builder for resolution tables using Coloring (CL)
299 class CLResolutionLayoutBuilder
300 super ResolutionLayoutBuilder
301
302 private var colorer: ResolutionColorer = new ResolutionColorer
303
304 init do super
305
306 # Compute resolved types colors
307 redef fun build_layout(elements) do
308 var result = new ResolutionLayout
309 result.ids = self.compute_ids(elements)
310 result.pos = self.colorer.colorize(elements)
311 return result
312 end
313 end
314
315 # Layout builder for resolution table using Perfect Hashing (PH)
316 class PHResolutionLayoutBuilder
317 super ResolutionLayoutBuilder
318
319 redef type LAYOUT: PHResolutionLayout
320
321 private var hasher: ResolutionHasher
322
323 init(operator: PHOperator) do self.hasher = new ResolutionHasher(operator)
324
325 # Compute resolved types masks and hashes
326 redef fun build_layout(elements) do
327 var result = new PHResolutionLayout
328 result.ids = self.compute_ids(elements)
329 result.pos = result.ids
330 result.masks = self.hasher.compute_masks(elements, result.ids)
331 result.hashes = self.hasher.compute_hashes(elements, result.ids, result.masks)
332 return result
333 end
334
335 redef fun compute_ids(elements) do
336 var ids = new HashMap[MType, Int]
337 var color = 1
338 for mclasstype, mclasstypes in elements do
339 for element in mclasstypes do
340 if ids.has_key(element) then continue
341 ids[element] = color
342 color += 1
343 end
344 end
345 return ids
346 end
347 end
348
349 # Colorers
350
351 abstract class AbstractColorer[E: Object]
352
353 private var core: Set[E] = new HashSet[E]
354 private var crown: Set[E] = new HashSet[E]
355 private var border: Set[E] = new HashSet[E]
356
357 private var coloration_result: Map[E, Int] = new HashMap[E, Int]
358
359 init do end
360
361 fun colorize(elements: Set[E]): Map[E, Int] do
362 tag_elements(elements)
363 build_conflicts_graph(elements)
364 colorize_elements(core)
365 colorize_elements(border)
366 colorize_elements(crown)
367 return coloration_result
368 end
369
370 # Colorize a collection of elements
371 private fun colorize_elements(elements: Set[E]) do
372 var min_color = 0
373
374 var lin = reverse_linearize(elements)
375 for element in lin do
376 var color = min_color
377 while not self.is_color_free(element, elements, color) do
378 color += 1
379 end
380 coloration_result[element] = color
381 color = min_color
382 end
383 end
384
385 # Check if a related element to the element already use the color
386 private fun is_color_free(element: E, elements: Set[E], color: Int): Bool do
387 if conflicts_graph.has_key(element) then
388 for st in conflicts_graph[element] do
389 if coloration_result.has_key(st) and coloration_result[st] == color then return false
390 end
391 end
392 for st in self.super_elements(element, elements) do
393 if coloration_result.has_key(st) and coloration_result[st] == color then return false
394 end
395 return true
396 end
397
398 # Tag elements as core, crown or border
399 private fun tag_elements(elements: Set[E]) do
400 for element in elements do
401 # Check if sub elements are all in single inheritance
402 var all_subelements_si = true
403 for subelem in self.sub_elements(element, elements) do
404 if self.is_element_mi(subelem, elements) then
405 all_subelements_si = false
406 break
407 end
408 end
409
410 # Tag as core, crown or border
411 if self.is_element_mi(element, elements) then
412 core.add_all(self.super_elements(element, elements))
413 core.add(element)
414 if all_subelements_si then
415 border.add(element)
416 end
417 else if not all_subelements_si then
418 core.add_all(self.super_elements(element, elements))
419 core.add(element)
420 else
421 crown.add(element)
422 end
423 end
424 end
425
426 # Conflicts graph of elements hierarchy (two types are in conflict if they have common subelements)
427 private fun build_conflicts_graph(elements: Set[E]) do
428 self.conflicts_graph = new HashMap[E, HashSet[E]]
429 var core = reverse_linearize(self.core)
430 for t in core do
431 for i in self.linear_extension(t, elements) do
432 if t == i then continue
433
434 var lin_i = self.linear_extension(i, elements)
435
436 for j in self.linear_extension(t, elements) do
437 if i == j or j == t then continue
438 var lin_j = self.linear_extension(j, elements)
439
440 var d_ij = lin_i - lin_j
441 var d_ji = lin_j - lin_i
442
443 for ed1 in d_ij do
444 if not conflicts_graph.has_key(ed1) then conflicts_graph[ed1] = new HashSet[E]
445 # add ed1 x ed2 to conflicts graph
446 for ed2 in d_ji do conflicts_graph[ed1].add(ed2)
447 end
448 for ed1 in d_ij do
449 if not conflicts_graph.has_key(ed1) then conflicts_graph[ed1] = new HashSet[E]
450 # add ed1 x ed2 to conflicts graph
451 for ed2 in d_ji do conflicts_graph[ed1].add(ed2)
452 end
453 end
454 end
455 end
456 end
457
458 private var conflicts_graph: nullable HashMap[E, Set[E]]
459
460 # cache for linear_extensions
461 private var linear_extensions_cache: Map[E, Array[E]] = new HashMap[E, Array[E]]
462
463 # Return a linear_extension of super_elements of the element
464 private fun linear_extension(element: E, elements: Set[E]): Array[E] do
465 if not self.linear_extensions_cache.has_key(element) then
466 var supers = new HashSet[E]
467 supers.add(element)
468 supers.add_all(self.super_elements(element, elements))
469 self.linear_extensions_cache[element] = self.linearize(supers)
470 end
471 return self.linear_extensions_cache[element]
472 end
473
474 private fun super_elements(element: E, elements: Set[E]): Set[E] is abstract
475 private fun sub_elements(element: E, elements: Set[E]): Set[E] is abstract
476 private fun is_element_mi(element: E, elements: Set[E]): Bool is abstract
477 private fun linearize(elements: Set[E]): Array[E] is abstract
478 private fun reverse_linearize(elements: Set[E]): Array[E] is abstract
479 end
480
481 # MType coloring
482 private class MTypeColorer
483 super AbstractColorer[MType]
484
485 var mmodule: MModule
486
487 init(mmodule: MModule) do self.mmodule = mmodule
488
489 redef fun super_elements(element, elements) do return self.mmodule.super_mtypes(element, elements)
490 redef fun is_element_mi(element, elements) do return self.super_elements(element, elements).length > 1
491 redef fun sub_elements(element, elements) do do return self.mmodule.sub_mtypes(element, elements)
492 redef fun linearize(elements) do return self.mmodule.linearize_mtypes(elements)
493 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mtypes(elements)
494 end
495
496 # MClass coloring
497 private class MClassColorer
498 super AbstractColorer[MClass]
499
500 private var mmodule: MModule
501
502 init(mmodule: MModule) do self.mmodule = mmodule
503
504 redef fun super_elements(element, elements) do return self.mmodule.super_mclasses(element)
505 fun parent_elements(element: MClass): Set[MClass] do return self.mmodule.parent_mclasses(element)
506 redef fun is_element_mi(element, elements) do return self.parent_elements(element).length > 1
507 redef fun sub_elements(element, elements) do do return self.mmodule.sub_mclasses(element)
508 redef fun linearize(elements) do return self.mmodule.linearize_mclasses(elements)
509 redef fun reverse_linearize(elements) do return self.mmodule.reverse_linearize_mclasses(elements)
510 end
511
512 # MProperty coloring
513 private class MPropertyColorer[E: MProperty]
514
515 private var mmodule: MModule
516 private var class_colorer: MClassColorer
517 private var coloration_result: Map[E, Int] = new HashMap[E, Int]
518
519 init(mmodule: MModule) do
520 self.mmodule = mmodule
521 self.class_colorer = new MClassColorer(mmodule)
522 end
523
524 fun colorize(mclasses: Set[MClass]): Map[E, Int] do
525 self.class_colorer.tag_elements(mclasses)
526 self.class_colorer.build_conflicts_graph(mclasses)
527 self.colorize_core(self.class_colorer.core)
528 self.colorize_crown(self.class_colorer.crown)
529 return self.coloration_result
530 end
531
532 # Colorize properties of the core hierarchy
533 private fun colorize_core(mclasses: Set[MClass]) do
534 var min_color = 0
535 for mclass in mclasses do
536 var color = min_color
537
538 # if the class is root, get the minimal color
539 if self.mmodule.parent_mclasses(mclass).length == 0 then
540 colorize_elements(self.properties(mclass), color)
541 else
542 # check last color used by parents
543 color = max_color(color, self.mmodule.parent_mclasses(mclass))
544 # check max color used in conflicts
545 if self.class_colorer.conflicts_graph.has_key(mclass) then
546 color = max_color(color, self.class_colorer.conflicts_graph[mclass])
547 end
548 colorize_elements(self.properties(mclass), color)
549 end
550 end
551 end
552
553 # Colorize properties of the crown hierarchy
554 private fun colorize_crown(mclasses: Set[MClass]) do
555 for mclass in mclasses do
556 colorize_elements(self.properties(mclass), max_color(0, self.mmodule.parent_mclasses(mclass)))
557 end
558 end
559
560 # Colorize a collection of mproperties given a starting color
561 private fun colorize_elements(elements: Collection[E], start_color: Int) do
562 for element in elements do
563 if self.coloration_result.has_key(element) then continue
564 self.coloration_result[element] = start_color
565 start_color += 1
566 end
567 end
568
569 private fun max_color(min_color: Int, mclasses: Collection[MClass]): Int do
570 var max_color = min_color
571
572 for mclass in mclasses do
573 for mproperty in self.properties(mclass) do
574 var color = min_color
575 if self.coloration_result.has_key(mproperty) then
576 color = self.coloration_result[mproperty]
577 if color >= max_color then max_color = color + 1
578 end
579 end
580 end
581 return max_color
582 end
583
584 # Filter properties
585 private fun properties(mclass: MClass): Set[E] do
586 var properties = new HashSet[E]
587 for mprop in self.mmodule.properties(mclass) do
588 if mprop isa E then properties.add(mprop)
589 end
590 return properties
591 end
592 end
593
594 # Colorer for type resolution table
595 class ResolutionColorer
596
597 private var coloration_result: Map[MType, Int] = new HashMap[MType, Int]
598
599 init do end
600
601 fun colorize(elements: Map[MClassType, Set[MType]]): Map[MType, Int] do
602 self.build_conflicts_graph(elements)
603 self.colorize_elements(elements)
604 return coloration_result
605 end
606
607 # Colorize a collection of elements
608 fun colorize_elements(elements: Map[MClassType, Set[MType]]) do
609 var min_color = 0
610 for mclasstype, mclasstypes in elements do
611 for element in mclasstypes do
612 if self.coloration_result.has_key(element) then continue
613 var color = min_color
614 while not self.is_color_free(element, color) do
615 color += 1
616 end
617 coloration_result[element] = color
618 color = min_color
619 end
620 end
621 end
622
623 # Check if a related element to the element already use the color
624 private fun is_color_free(element: MType, color: Int): Bool do
625 if conflicts_graph.has_key(element) then
626 for st in conflicts_graph[element] do
627 if coloration_result.has_key(st) and coloration_result[st] == color then return false
628 end
629 end
630 return true
631 end
632
633 # look for unanchored types generated by the same type
634 private fun build_conflicts_graph(elements: Map[MClassType, Set[MType]]) do
635 for mclasstype, mtypes in elements do
636 for mtype in mtypes do
637 for otype in mtypes do
638 if otype == mtype then continue
639 self.add_conflict(mtype, otype)
640 end
641 end
642 end
643 end
644
645 private var conflicts_graph: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
646
647 private fun add_conflict(mtype: MType, otype: MType) do
648 if mtype == otype then return
649 if not self.conflicts_graph.has_key(mtype) then self.conflicts_graph[mtype] = new HashSet[MType]
650 self.conflicts_graph[mtype].add(otype)
651 if not self.conflicts_graph.has_key(otype) then self.conflicts_graph[otype] = new HashSet[MType]
652 self.conflicts_graph[otype].add(mtype)
653 end
654 end
655
656 # Perfect hashers
657
658 # Abstract Perfect Hashing
659 private abstract class AbstractHasher[E: Object]
660
661 var operator: PHOperator
662
663 init(operator: PHOperator) do self.operator = operator
664
665 fun compute_masks(elements: Set[E], ids: Map[E, Int]): Map[E, Int] do
666 var masks = new HashMap[E, Int]
667 for element in elements do
668 var supers = new HashSet[E]
669 supers.add_all(self.super_elements(element, elements))
670 supers.add(element)
671 masks[element] = compute_mask(supers, ids)
672 end
673 return masks
674 end
675
676 fun compute_mask(supers: Set[E], ids: Map[E, Int]): Int do
677 var mask = 0
678 loop
679 var used = new List[Int]
680 for sup in supers do
681 var res = operator.op(mask, ids[sup])
682 if used.has(res) then
683 break
684 else
685 used.add(res)
686 end
687 end
688 if used.length == supers.length then break
689 mask += 1
690 end
691 return mask
692 end
693
694 fun compute_hashes(elements: Set[E], ids: Map[E, Int], masks: Map[E, Int]): Map[E, Map[E, Int]] do
695 var hashes = new HashMap[E, Map[E, Int]]
696 for element in elements do
697 var supers = new HashSet[E]
698 supers.add_all(self.super_elements(element, elements))
699 supers.add(element)
700 var inhashes = new HashMap[E, Int]
701 var mask = masks[element]
702 for sup in supers do
703 inhashes[sup] = operator.op(mask, ids[sup])
704 end
705 hashes[element] = inhashes
706 end
707 return hashes
708 end
709
710 fun super_elements(element: E, elements: Set[E]): Set[E] is abstract
711 end
712
713 # Abstract operator used for perfect hashing
714 abstract class PHOperator
715 fun op(mask: Int, id:Int): Int is abstract
716 end
717
718 # Hashing using modulo (MOD) operator
719 # slower but compact
720 class PHModOperator
721 super PHOperator
722 init do end
723 redef fun op(mask, id) do return mask % id
724 end
725
726 # Hashing using binary and (AND) operator
727 # faster but sparse
728 class PHAndOperator
729 super PHOperator
730 init do end
731 redef fun op(mask, id) do return mask.bin_and(id)
732 end
733
734 # MType Perfect Hashing
735 private class MTypeHasher
736 super AbstractHasher[MType]
737
738 var mmodule: MModule
739
740 init(mmodule: MModule, operator: PHOperator) do
741 super(operator)
742 self.mmodule = mmodule
743 end
744
745 redef fun super_elements(element, elements) do return self.mmodule.super_mtypes(element, elements)
746 end
747
748 # MClass Perfect Hashing
749 private class MClassHasher
750 super AbstractHasher[MClass]
751
752 private var mmodule: MModule
753
754 init(mmodule: MModule, operator: PHOperator) do
755 super(operator)
756 self.mmodule = mmodule
757 end
758
759 redef fun super_elements(element, elements) do return self.mmodule.super_mclasses(element)
760 end
761
762 # Resolution tables Perfect Hashing (PH)
763 private class ResolutionHasher
764
765 var operator: PHOperator
766
767 init(operator: PHOperator) do self.operator = operator
768
769 fun compute_masks(elements: Map[MClassType, Set[MType]], ids: Map[MType, Int]): Map[MClassType, Int] do
770 var masks = new HashMap[MClassType, Int]
771 for mclasstype, mtypes in elements do
772 masks[mclasstype] = compute_mask(mtypes, ids)
773 end
774 return masks
775 end
776
777 private fun compute_mask(mtypes: Set[MType], ids: Map[MType, Int]): Int do
778 var mask = 0
779 loop
780 var used = new List[Int]
781 for mtype in mtypes do
782 var res = operator.op(mask, ids[mtype])
783 if used.has(res) then
784 break
785 else
786 used.add(res)
787 end
788 end
789 if used.length == mtypes.length then break
790 mask += 1
791 end
792 return mask
793 end
794
795 fun compute_hashes(elements: Map[MClassType, Set[MType]], ids: Map[MType, Int], masks: Map[MClassType, Int]): Map[MClassType, Map[MType, Int]] do
796 var hashes = new HashMap[MClassType, Map[MType, Int]]
797 for mclasstype, mtypes in elements do
798 var mask = masks[mclasstype]
799 var inhashes = new HashMap[MType, Int]
800 for mtype in mtypes do
801 inhashes[mtype] = operator.op(mask, ids[mtype])
802 end
803 hashes[mclasstype] = inhashes
804 end
805 return hashes
806 end
807 end
808
809 # live unanchored coloring
810 class UnanchoredTypeColoring
811
812 private var coloration_result: Map[MType, Int] = new HashMap[MType, Int]
813 private var conflicts_graph: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
814
815 init do end
816
817 fun colorize(elements: Map[MClassType, Set[MType]]): Map[MType, Int] do
818 build_conflicts_graph(elements)
819 colorize_elements(elements)
820 return coloration_result
821 end
822
823 # Colorize a collection of elements
824 fun colorize_elements(elements: Map[MClassType, Set[MType]]) do
825 var min_color = 0
826 for mclasstype, mclasstypes in elements do
827 for element in mclasstypes do
828 if self.coloration_result.has_key(element) then continue
829 var color = min_color
830 while not self.is_color_free(element, color) do
831 color += 1
832 end
833 coloration_result[element] = color
834 color = min_color
835 end
836 end
837 end
838
839 # Check if a related element to the element already use the color
840 private fun is_color_free(element: MType, color: Int): Bool do
841 if conflicts_graph.has_key(element) then
842 for st in conflicts_graph[element] do
843 if coloration_result.has_key(st) and coloration_result[st] == color then return false
844 end
845 end
846 return true
847 end
848
849 # look for unanchored types generated by the same type
850 private fun build_conflicts_graph(elements: Map[MClassType, Set[MType]]) do
851 for mclasstype, mtypes in elements do
852 for mtype in mtypes do
853 for otype in mtypes do
854 if otype == mtype then continue
855 self.add_conflict(mtype, otype)
856 end
857 end
858 end
859 end
860
861 private fun add_conflict(mtype: MType, otype: MType) do
862 if mtype == otype then return
863 if not self.conflicts_graph.has_key(mtype) then self.conflicts_graph[mtype] = new HashSet[MType]
864 self.conflicts_graph[mtype].add(otype)
865 if not self.conflicts_graph.has_key(otype) then self.conflicts_graph[otype] = new HashSet[MType]
866 self.conflicts_graph[otype].add(mtype)
867 end
868 end
869
870 class NaiveUnanchoredTypeColoring
871 super UnanchoredTypeColoring
872
873 init do end
874
875 redef fun colorize_elements(elements: Map[MClassType, Set[MType]]) do
876 var color = 0
877 for mclasstype, mclasstypes in elements do
878 for element in mclasstypes do
879 coloration_result[element] = color
880 color += 1
881 end
882 end
883 end
884 end
885
886 abstract class UnanchoredTypePerfectHashing
887 super NaiveUnanchoredTypeColoring
888
889 private var masks: Map[MClassType, Int] = new HashMap[MClassType, Int]
890
891 init do end
892
893 redef fun colorize_elements(elements: Map[MClassType, Set[MType]]) do
894 var color = 1
895 for mclasstype, mclasstypes in elements do
896 for element in mclasstypes do
897 coloration_result[element] = color
898 color += 1
899 end
900 end
901 end
902
903 fun compute_masks(elements: Map[MClassType, Set[MType]]): Map[MClassType, Int] do
904 for mclasstype, mtypes in elements do
905 self.masks[mclasstype] = compute_mask(mtypes)
906 end
907 return self.masks
908 end
909
910 private fun compute_mask(mtypes: Set[MType]): Int do
911 var mask = 0
912 loop
913 var used = new List[Int]
914 for mtype in mtypes do
915 var res = op(mask, self.coloration_result[mtype])
916 if used.has(res) then
917 break
918 else
919 used.add(res)
920 end
921 end
922 if used.length == mtypes.length then break
923 mask += 1
924 end
925 return mask
926 end
927
928 private fun op(mask: Int, id:Int): Int is abstract
929 private fun phash(id: Int, mask: Int): Int do return op(mask, id)
930 end
931
932 class UnanchoredTypeModPerfectHashing
933 super UnanchoredTypePerfectHashing
934 init do end
935 redef fun op(mask, id) do return mask % id
936 end
937
938 class UnanchoredTypeAndPerfectHashing
939 super UnanchoredTypePerfectHashing
940 init do end
941 redef fun op(mask, id) do return mask.bin_and(id)
942 end
943
944
945 # Utils
946
947 redef class HashSet[E]
948 init from(elements: Collection[E]) do
949 init
950 self.add_all(elements)
951 end
952 end
953
954 redef class Array[E]
955 init from(elements: Collection[E]) do
956 init
957 self.add_all(elements)
958 end
959
960 # Return a new Array with the elements only contened in 'self' and not in 'o'
961 fun -(o: Array[E]): Array[E] do
962 var res = new Array[E]
963 for e in self do if not o.has(e) then res.add(e)
964 return res
965 end
966 end
967
968 redef class MModule
969
970 # Return a linearization of a set of mtypes
971 private fun linearize_mtypes(mtypes: Set[MType]): Array[MType] do
972 var lin = new Array[MType].from(mtypes)
973 var sorter = new TypeSorter(self)
974 sorter.sort(lin)
975 return lin
976 end
977
978 # Return a reverse linearization of a set of mtypes
979 private fun reverse_linearize_mtypes(mtypes: Set[MType]): Array[MType] do
980 var lin = new Array[MType].from(mtypes)
981 var sorter = new ReverseTypeSorter(self)
982 sorter.sort(lin)
983 return lin
984 end
985
986 # Return super types of a `mtype` in `self`
987 private fun super_mtypes(mtype: MType, mtypes: Set[MType]): Set[MType] do
988 if not self.super_mtypes_cache.has_key(mtype) then
989 var supers = new HashSet[MType]
990 for otype in mtypes do
991 if otype == mtype then continue
992 if mtype.is_subtype(self, null, otype) then
993 supers.add(otype)
994 end
995 end
996 self.super_mtypes_cache[mtype] = supers
997 end
998 return self.super_mtypes_cache[mtype]
999 end
1000
1001 private var super_mtypes_cache: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
1002
1003 # Return all sub mtypes (directs and indirects) of a `mtype` in `self`
1004 private fun sub_mtypes(mtype: MType, mtypes: Set[MType]): Set[MType] do
1005 if not self.sub_mtypes_cache.has_key(mtype) then
1006 var subs = new HashSet[MType]
1007 for otype in mtypes do
1008 if otype == mtype then continue
1009 if otype.is_subtype(self, null, mtype) then
1010 subs.add(otype)
1011 end
1012 end
1013 self.sub_mtypes_cache[mtype] = subs
1014 end
1015 return self.sub_mtypes_cache[mtype]
1016 end
1017
1018 private var sub_mtypes_cache: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
1019
1020 # Return a linearization of a set of mclasses
1021 private fun linearize_mclasses(mclasses: Set[MClass]): Array[MClass] do
1022 var lin = new Array[MClass].from(mclasses)
1023 var sorter = new ClassSorter(self)
1024 sorter.sort(lin)
1025 return lin
1026 end
1027
1028 # Return a reverse linearization of a set of mtypes
1029 private fun reverse_linearize_mclasses(mclasses: Set[MClass]): Array[MClass] do
1030 var lin = new Array[MClass].from(mclasses)
1031 var sorter = new ReverseClassSorter(self)
1032 sorter.sort(lin)
1033 return lin
1034 end
1035
1036 # Return all super mclasses (directs and indirects) of a `mclass` in `self`
1037 private fun super_mclasses(mclass: MClass): Set[MClass] do
1038 if not self.super_mclasses_cache.has_key(mclass) then
1039 var supers = new HashSet[MClass]
1040 if self.flatten_mclass_hierarchy.has(mclass) then
1041 for sup in self.flatten_mclass_hierarchy[mclass].greaters do
1042 if sup == mclass then continue
1043 supers.add(sup)
1044 end
1045 end
1046 self.super_mclasses_cache[mclass] = supers
1047 end
1048 return self.super_mclasses_cache[mclass]
1049 end
1050
1051 private var super_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
1052
1053 # Return all parents of a `mclass` in `self`
1054 private fun parent_mclasses(mclass: MClass): Set[MClass] do
1055 if not self.parent_mclasses_cache.has_key(mclass) then
1056 var parents = new HashSet[MClass]
1057 if self.flatten_mclass_hierarchy.has(mclass) then
1058 for sup in self.flatten_mclass_hierarchy[mclass].direct_greaters do
1059 if sup == mclass then continue
1060 parents.add(sup)
1061 end
1062 end
1063 self.parent_mclasses_cache[mclass] = parents
1064 end
1065 return self.parent_mclasses_cache[mclass]
1066 end
1067
1068 private var parent_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
1069
1070 # Return all sub mclasses (directs and indirects) of a `mclass` in `self`
1071 private fun sub_mclasses(mclass: MClass): Set[MClass] do
1072 if not self.sub_mclasses_cache.has_key(mclass) then
1073 var subs = new HashSet[MClass]
1074 if self.flatten_mclass_hierarchy.has(mclass) then
1075 for sub in self.flatten_mclass_hierarchy[mclass].smallers do
1076 if sub == mclass then continue
1077 subs.add(sub)
1078 end
1079 end
1080 self.sub_mclasses_cache[mclass] = subs
1081 end
1082 return self.sub_mclasses_cache[mclass]
1083 end
1084
1085 private var sub_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
1086
1087 # All 'mproperties' associated to all 'mclassdefs' of `mclass`
1088 private fun properties(mclass: MClass): Set[MProperty] do
1089 if not self.properties_cache.has_key(mclass) then
1090 var properties = new HashSet[MProperty]
1091 var parents = self.super_mclasses(mclass)
1092 for parent in parents do
1093 properties.add_all(self.properties(parent))
1094 end
1095
1096 for mclassdef in mclass.mclassdefs do
1097 for mpropdef in mclassdef.mpropdefs do
1098 properties.add(mpropdef.mproperty)
1099 end
1100 end
1101 self.properties_cache[mclass] = properties
1102 end
1103 return properties_cache[mclass]
1104 end
1105
1106 private var properties_cache: Map[MClass, Set[MProperty]] = new HashMap[MClass, Set[MProperty]]
1107 end
1108
1109 # A sorter for linearize list of types
1110 class TypeSorter
1111 super AbstractSorter[MType]
1112
1113 private var mmodule: MModule
1114
1115 init(mmodule: MModule) do self.mmodule = mmodule
1116
1117 redef fun compare(a, b) do
1118 if a == b then
1119 return 0
1120 else if a.is_subtype(self.mmodule, null, b) then
1121 return -1
1122 end
1123 return 1
1124 end
1125 end
1126
1127 # A sorter for reverse linearization
1128 class ReverseTypeSorter
1129 super TypeSorter
1130
1131 init(mmodule: MModule) do end
1132
1133 redef fun compare(a, b) do
1134 if a == b then
1135 return 0
1136 else if a.is_subtype(self.mmodule, null, b) then
1137 return 1
1138 end
1139 return -1
1140 end
1141 end
1142
1143 # A sorter for linearize list of classes
1144 private class ClassSorter
1145 super AbstractSorter[MClass]
1146
1147 var mmodule: MModule
1148
1149 redef fun compare(a, b) do
1150 if a == b then
1151 return 0
1152 else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
1153 return -1
1154 end
1155 return 1
1156 end
1157 end
1158
1159 # A sorter for reverse linearization
1160 private class ReverseClassSorter
1161 super AbstractSorter[MClass]
1162
1163 var mmodule: MModule
1164
1165 redef fun compare(a, b) do
1166 if a == b then
1167 return 0
1168 else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
1169 return 1
1170 end
1171 return -1
1172 end
1173 end