5 // Alexander Chebaturkin (chebaturkin@gmail.com)
7 // Copyright (C) 2011 Alexander Chebaturkin
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Collections.Generic;
33 using Mono.CodeContracts.Static.DataStructures;
34 using Mono.CodeContracts.Static.Extensions;
36 namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis.SymbolicGraph {
37 class SymGraph<TFunc, TADomain> : ISymGraph<TFunc, TADomain, SymGraph<TFunc, TADomain>>
38 where TFunc : IEquatable<TFunc>, IConstantInfo
39 where TADomain : IAbstractDomainForEGraph<TADomain>, IEquatable<TADomain> {
40 public const bool DoIncrementalJoin = false;
41 private static int egraphIdGenerator;
42 private static SymGraph<TFunc, TADomain> BottomValue;
43 public readonly SymValue BottomPlaceHolder;
44 public readonly SymGraph<TFunc, TADomain> Parent;
45 public readonly TADomain UnderlyingTopValue;
47 private readonly SymValue const_root;
48 private readonly int egraph_id;
49 private readonly int history_size;
51 private readonly SymGraph<TFunc, TADomain> root_graph;
53 private readonly TADomain underlying_bottom_value;
54 private IImmutableMap<SymValue, TADomain> abs_map;
55 private IImmutableMap<SymValue, SymValue> forw_map;
56 private bool is_immutable;
58 public SymGraph (TADomain topValue, TADomain bottomValue)
59 : this (topValue, bottomValue, false)
61 if (BottomValue != null)
63 BottomValue = new SymGraph<TFunc, TADomain> (topValue, bottomValue, false);
66 private SymGraph (TADomain topValue, TADomain bottomValue, bool _)
68 this.egraph_id = egraphIdGenerator++;
69 this.const_root = FreshSymbol ();
71 TermMap = DoubleImmutableMap<SymValue, TFunc, SymValue>.Empty (SymValue.GetUniqueKey);
72 MultiEdgeMap = DoubleImmutableMap<SymValue, MultiEdge<TFunc, TADomain>, LispList<SymValue>>.Empty (SymValue.GetUniqueKey);
73 this.abs_map = ImmutableIntKeyMap<SymValue, TADomain>.Empty (SymValue.GetUniqueKey);
74 this.forw_map = ImmutableIntKeyMap<SymValue, SymValue>.Empty (SymValue.GetUniqueKey);
75 EqualTermsMap = ImmutableIntKeyMap<SymValue, LispList<SymGraphTerm<TFunc>>>.Empty (SymValue.GetUniqueKey);
76 EqualMultiTermsMap = ImmutableIntKeyMap<SymValue, SymGraphTerm<TFunc>>.Empty (SymValue.GetUniqueKey);
78 this.BottomPlaceHolder = FreshSymbol ();
79 this.abs_map = this.abs_map.Add (this.BottomPlaceHolder, bottomValue);
80 this.is_immutable = false;
81 this.history_size = 1;
83 this.root_graph = this;
85 this.UnderlyingTopValue = topValue;
86 this.underlying_bottom_value = bottomValue;
89 private SymGraph (SymGraph<TFunc, TADomain> from)
91 this.egraph_id = egraphIdGenerator++;
92 this.const_root = from.const_root;
93 this.BottomPlaceHolder = from.BottomPlaceHolder;
94 TermMap = from.TermMap;
95 MultiEdgeMap = from.MultiEdgeMap;
96 IdGenerator = from.IdGenerator;
97 this.abs_map = from.abs_map;
98 this.forw_map = from.forw_map;
99 EqualTermsMap = from.EqualTermsMap;
100 EqualMultiTermsMap = from.EqualMultiTermsMap;
101 this.UnderlyingTopValue = from.UnderlyingTopValue;
102 this.underlying_bottom_value = from.underlying_bottom_value;
103 Updates = from.Updates;
105 this.root_graph = from.root_graph;
106 this.history_size = from.history_size + 1;
108 from.MarkAsImmutable ();
111 public IImmutableMap<SymValue, SymGraphTerm<TFunc>> EqualMultiTermsMap { get; private set; }
112 public IImmutableMap<SymValue, LispList<SymGraphTerm<TFunc>>> EqualTermsMap { get; private set; }
113 public DoubleImmutableMap<SymValue, MultiEdge<TFunc, TADomain>, LispList<SymValue>> MultiEdgeMap { get; private set; }
114 public DoubleImmutableMap<SymValue, TFunc, SymValue> TermMap { get; private set; }
115 public int IdGenerator { get; private set; }
116 public LispList<Update<TFunc, TADomain>> Updates { get; private set; }
118 public bool IsImmutable
120 get { return this.is_immutable; }
123 private int LastSymbolId
125 get { return IdGenerator; }
128 public SymValue this [SymValue[] args, TFunc function]
132 int len = args.Length;
133 for (int i = 0; i < len; i++)
134 args [i] = Find (args [i]);
136 SymValue candidate = FindCandidate (args, function);
137 if (candidate != null)
139 candidate = FreshSymbol ();
140 for (int i = 0; i < len; i++) {
141 var edge = new MultiEdge<TFunc, TADomain> (function, i, len);
142 MultiEdgeMap = MultiEdgeMap.Add (args [i], edge, MultiEdgeMap [args [i], edge].Cons (candidate));
144 EqualMultiTermsMap = EqualMultiTermsMap.Add (candidate, new SymGraphTerm<TFunc> (function, args));
145 AddMultiEdgeUpdate (args, function);
150 int len = args.Length;
151 for (int i = 0; i < len; i++)
152 args [i] = Find (args [i]);
154 bool isTermEqual = true;
155 SymGraphTerm<TFunc> term = EqualMultiTermsMap [value];
156 if (term.Args != null) {
157 for (int i = 0; i < len; i++) {
158 if (term.Args [i] != args [i]) {
165 for (int i = 0; i < len; i++) {
166 var edge = new MultiEdge<TFunc, TADomain> (function, i, len);
167 LispList<SymValue> list = MultiEdgeMap [args [i], edge];
168 if (isTermEqual && !LispList<SymValue>.Contains (list, value))
171 MultiEdgeMap = MultiEdgeMap.Add (args [i], edge, list.Cons (value));
175 EqualMultiTermsMap = EqualMultiTermsMap.Add (value, new SymGraphTerm<TFunc> (function, args));
176 AddMultiEdgeUpdate (args, function);
180 public SymValue this [TFunc function, params SymValue[] args]
182 get { return this [args, function]; }
185 private SymValue this [SymValue source, TFunc function]
189 source = Find (source);
190 SymValue sv = TermMap [source, function];
193 key = FreshSymbol ();
194 TermMap = TermMap.Add (source, function, key);
195 EqualTermsMap = EqualTermsMap.Add (key, LispList<SymGraphTerm<TFunc>>.Cons (new SymGraphTerm<TFunc> (function, source), null));
196 AddEdgeUpdate (source, function);
204 source = Find (source);
205 value = Find (value);
207 TermMap = TermMap.Add (source, function, value);
208 LispList<SymGraphTerm<TFunc>> rest = EqualTermsMap [value];
209 if (rest.IsEmpty () || (!rest.Head.Function.Equals (function) || rest.Head.Args [0] != source))
210 EqualTermsMap = EqualTermsMap.Add (value, rest.Cons (new SymGraphTerm<TFunc> (function, source)));
212 AddEdgeUpdate (source, function);
216 public IEnumerable<Pair<SymValue, SymGraphTerm<TFunc>>> ValidMultiTerms {
219 foreach (SymValue sv in EqualMultiTermsMap.Keys) {
220 SymGraphTerm<TFunc> term = EqualMultiTermsMap [sv];
221 if (IsValidMultiTerm (term))
222 yield return new Pair<SymValue, SymGraphTerm<TFunc>> (sv, term);
227 public SymValue ConstRoot
229 get { return this.const_root; }
232 #region ISymGraph<TFunc,TADomain,SymGraph<TFunc,TADomain>> Members
233 public TADomain this [SymValue symbol]
237 symbol = Find (symbol);
238 if (this.abs_map.ContainsKey (symbol))
239 return this.abs_map [symbol];
241 return this.UnderlyingTopValue;
245 SymValue newSym = Find (symbol);
246 if (this [symbol].Equals (value))
248 AddAbstractValueUpdate (newSym);
250 this.abs_map = this.abs_map.Remove (newSym);
252 this.abs_map = this.abs_map.Add (newSym, value);
256 public SymValue this [TFunc function]
258 get { return this [this.const_root, function]; }
259 set { this [this.const_root, function] = value; }
262 public SymValue this [TFunc function, SymValue arg]
264 get { return this [arg, function]; }
265 set { this [arg, function] = value; }
268 public IEnumerable<TFunc> Constants
270 get { return TermMap.Keys2 (this.const_root); }
273 public IEnumerable<SymValue> Variables
275 get { return TermMap.Keys1; }
278 public SymGraph<TFunc, TADomain> Top
280 get { return new SymGraph<TFunc, TADomain> (this.UnderlyingTopValue, this.underlying_bottom_value); }
283 public SymGraph<TFunc, TADomain> Bottom
287 if (BottomValue == null) {
288 BottomValue = new SymGraph<TFunc, TADomain> (this.UnderlyingTopValue, this.underlying_bottom_value);
289 BottomValue.MarkAsImmutable ();
297 get { return TermMap.Keys2Count (this.const_root) == 0; }
302 get { return this == BottomValue; }
305 public SymValue FreshSymbol ()
307 return new SymValue (++IdGenerator);
310 public SymValue TryLookup (TFunc function)
312 return LookupWithoutManifesting (this.const_root, function);
315 public SymValue TryLookup (TFunc function, SymValue arg)
317 return LookupWithoutManifesting (arg, function);
320 public void Eliminate (TFunc function, SymValue arg)
322 SymValue value = Find (arg);
323 DoubleImmutableMap<SymValue, TFunc, SymValue> newTermMap = TermMap.Remove (value, function);
324 if (newTermMap == TermMap)
326 TermMap = newTermMap;
327 AddEliminateEdgeUpdate (value, function);
330 public void Eliminate (TFunc function)
332 TermMap = TermMap.Remove (this.const_root, function);
333 AddEliminateEdgeUpdate (this.const_root, function);
336 public void EliminateAll (SymValue arg)
338 SymValue value = Find (arg);
339 AddEliminateAllUpdate (value);
340 TermMap = TermMap.RemoveAll (value);
341 this [arg] = this.UnderlyingTopValue;
344 public void AssumeEqual (SymValue v1, SymValue v2)
346 var workList = new WorkList<EqualityPair<TFunc, TADomain>> ();
347 SymValue sv1 = Find (v1);
348 SymValue sv2 = Find (v2);
350 if (TryPushEquality (workList, sv1, sv2))
351 AddEqualityUpdate (sv1, sv2);
353 DrainEqualityWorkList (workList);
356 public bool IsEqual (SymValue v1, SymValue v2)
358 return Find (v1) == Find (v2);
361 public IEnumerable<TFunc> Functions (SymValue sv)
363 return TermMap.Keys2 (Find (sv));
366 public IEnumerable<SymGraphTerm<TFunc>> EqTerms (SymValue sv)
368 foreach (var term in EqualTermsMap [Find (sv)].AsEnumerable ()) {
369 if (TryLookup (term.Function, term.Args) == sv)
374 public SymGraph<TFunc, TADomain> Clone ()
376 return new SymGraph<TFunc, TADomain> (this);
379 public SymGraph<TFunc, TADomain> Join (SymGraph<TFunc, TADomain> that, bool widening, out bool weaker)
382 SymGraph<TFunc, TADomain> join = Join (that, out info, widening);
383 weaker = info.Changed;
387 public SymGraph<TFunc, TADomain> Join (SymGraph<TFunc, TADomain> that, out IMergeInfo mergeInfo, bool widen)
389 SymGraph<TFunc, TADomain> egraph = this;
391 SymGraph<TFunc, TADomain> commonTail = ComputeCommonTail (egraph, that, out updateSize);
392 bool hasCommonTail = true;
393 if (commonTail == null)
394 hasCommonTail = false;
396 bool doingIncrementalJoin = hasCommonTail & commonTail != egraph.root_graph & !widen & DoIncrementalJoin;
400 if (DebugOptions.Debug)
402 Console.WriteLine ("SymGraph {0}", widen ? "widen" : "join");
403 if (commonTail != null)
404 Console.WriteLine ("Last common symbol: {0}", commonTail.LastSymbolId);
406 Console.WriteLine (" Doing {0}", doingIncrementalJoin ? "incremental join" : "full join");
409 SymGraph<TFunc, TADomain> result;
410 MergeInfo<TFunc, TADomain> mergeState;
411 if (doingIncrementalJoin) {
412 result = new SymGraph<TFunc, TADomain> (commonTail);
413 mergeState = new MergeInfo<TFunc, TADomain> (result, egraph, that, widen);
414 mergeState.Replay (commonTail);
415 mergeState.Commit ();
417 result = new SymGraph<TFunc, TADomain> (commonTail);
418 mergeState = new MergeInfo<TFunc, TADomain> (result, egraph, that, widen);
419 mergeState.ReplayEliminations (commonTail);
420 mergeState.AddMapping (egraph.const_root, that.const_root, result.const_root);
421 mergeState.JoinSymbolicValue (egraph.const_root, that.const_root, result.const_root);
422 mergeState.Commit ();
424 mergeInfo = mergeState;
426 if (DebugOptions.Debug)
428 Console.WriteLine (" Result update size {0}", result.Updates.Length ());
429 Console.WriteLine ("Done with Egraph join: changed = {0}", mergeInfo.Changed ? 1 : 0);
435 public void Dump (TextWriter tw)
437 var set = new HashSet<SymValue> ();
438 var workList = new WorkList<SymValue> ();
439 IImmutableMap<SymValue, int> triggers = ImmutableIntKeyMap<SymValue, int>.Empty (SymValue.GetUniqueKey);
440 tw.WriteLine ("EGraphId: {0}", this.egraph_id);
441 tw.WriteLine ("LastSymbolId: {0}", LastSymbolId);
443 foreach (TFunc function in TermMap.Keys2 (this.const_root)) {
444 SymValue sv = this [this.const_root, function];
445 tw.WriteLine ("{0} = {1}", function, sv);
449 while (!workList.IsEmpty ()) {
450 SymValue sv = workList.Pull ();
454 foreach (TFunc function in TermMap.Keys2 (sv)) {
455 SymValue target = this [sv, function];
457 tw.WriteLine ("{0}({2}) = {1})", function, target, sv);
458 workList.Add (target);
460 foreach (var edge in MultiEdgeMap.Keys2 (sv)) {
461 foreach (SymValue target in MultiEdgeMap [sv, edge].AsEnumerable ()) {
462 if (!UpdateTrigger (target, edge, ref triggers))
464 SymGraphTerm<TFunc> term = EqualMultiTermsMap [target];
465 if (term.Args != null) {
466 tw.WriteLine ("{0}({1}) = {2}",
468 term.Args.ToString (", "), target);
469 workList.Add (target);
475 tw.WriteLine ("**Abstract value map");
476 foreach (SymValue sv in set) {
477 TADomain abstractValue = this [sv];
478 if (!abstractValue.IsTop)
479 tw.WriteLine ("{0} -> {1}", sv, abstractValue);
484 #region Implementation of IAbstractDomain<SymGraph<Constant,AbstractValue>>
485 public SymGraph<TFunc, TADomain> Meet (SymGraph<TFunc, TADomain> that)
487 if (this == that || IsBottom || that.IsTop)
489 if (that.IsBottom || IsTop)
495 public bool LessEqual (SymGraph<TFunc, TADomain> that)
497 IImmutableMap<SymValue, LispList<SymValue>> forwardMap;
498 IImmutableMap<SymValue, SymValue> backwardMap;
500 return LessEqual (that, out forwardMap, out backwardMap);
503 public SymGraph<TFunc, TADomain> ImmutableVersion ()
509 public bool LessEqual (SymGraph<TFunc, TADomain> that,
510 out IImmutableMap<SymValue, LispList<SymValue>> forward,
511 out IImmutableMap<SymValue, SymValue> backward)
513 if (!IsSameEGraph (that))
514 return InternalLessEqual (this, that, out forward, out backward);
522 public bool HasAllBottomFields (SymValue sv)
527 return this [sv].HasAllBottomFields;
530 public SymValue LookupOrManifest (TFunc function, SymValue arg, out bool fresh)
532 int oldCnt = IdGenerator;
533 SymValue result = this [function, arg];
535 fresh = oldCnt < IdGenerator;
539 public SymValue TryLookup (TFunc function, params SymValue[] args)
541 if (args.Length == 0 || args.Length == 1)
542 return LookupWithoutManifesting (this.const_root, function);
543 return LookupWithoutManifesting (args, function);
546 public SymValue LookupWithoutManifesting (SymValue sv, TFunc function)
551 SymValue result = TermMap [sv, function];
555 return Find (result);
558 public SymValue LookupWithoutManifesting (SymValue[] args, TFunc function)
560 int length = args.Length;
561 for (int i = 0; i < length; i++)
562 args [i] = Find (args [i]);
563 return FindCandidate (args, function);
566 public SymValue LookupOrBottomPlaceHolder (SymValue arg, TFunc function, out bool isPlaceHolder)
568 SymValue result = LookupWithoutManifesting (arg, function);
570 isPlaceHolder = result == null;
571 return isPlaceHolder ? this.BottomPlaceHolder : result;
574 private SymValue Find (SymValue v)
576 SymValue forw = this.forw_map [v];
583 private bool IsOldSymbol (SymValue sv)
585 if (this.Parent == null)
587 return sv.UniqueId <= this.Parent.LastSymbolId;
590 private SymValue FindCandidate (SymValue[] args, TFunc function)
592 int length = args.Length;
593 var multiEdge = new MultiEdge<TFunc, TADomain> (function, 0, length);
594 for (LispList<SymValue> list = MultiEdgeMap [args [0], multiEdge]; list != null; list = list.Tail) {
595 SymGraphTerm<TFunc> term = EqualMultiTermsMap [list.Head];
596 if (term.Args.Length == length) {
599 for (int i = 0; i < length; ++i) {
600 if (Find (term.Args [i]) != args [i]) {
613 private bool TryPushEquality (WorkList<EqualityPair<TFunc, TADomain>> workList, SymValue sv1, SymValue sv2)
616 workList.Add (new EqualityPair<TFunc, TADomain> (sv1, sv2));
623 private void DrainEqualityWorkList (WorkList<EqualityPair<TFunc, TADomain>> workList)
625 while (!workList.IsEmpty ()) {
626 EqualityPair<TFunc, TADomain> equalityPair = workList.Pull ();
627 SymValue sv1 = Find (equalityPair.Sv1);
628 SymValue sv2 = Find (equalityPair.Sv2);
630 if (sv1.UniqueId < sv2.UniqueId) {
636 foreach (TFunc function in Functions (sv1)) {
637 SymValue v2 = LookupWithoutManifesting (sv2, function);
639 this [sv2, function] = this [sv1, function];
641 TryPushEquality (workList, this [sv1, function], v2);
643 TADomain thisValue = this [sv1];
644 TADomain thatValue = this [sv2];
645 foreach (var elem in EqualTermsMap [sv1].AsEnumerable ())
646 EqualTermsMap = EqualTermsMap.Add (sv2, EqualTermsMap [sv2].Cons (elem));
648 this.forw_map = this.forw_map.Add (sv1, sv2);
649 this [sv2] = thisValue.Meet (thatValue);
654 private IEnumerable<MultiEdge<TFunc, TADomain>> MultiEdges (SymValue sv)
656 return MultiEdgeMap.Keys2 (Find (sv));
659 public IEnumerable<SymGraphTerm<TFunc>> EqMultiTerms (SymValue sv)
661 SymGraphTerm<TFunc> term = EqualMultiTermsMap [sv];
662 if (term.Args != null && IsValidMultiTerm (term))
666 public bool IsValidSymbol (SymValue sv)
668 return EqualTermsMap.ContainsKey (sv);
671 private bool IsValidMultiTerm (SymGraphTerm<TFunc> term)
673 return LookupWithoutManifesting (term.Args, term.Function) != null;
676 private static SymGraph<TFunc, TADomain> ComputeCommonTail (SymGraph<TFunc, TADomain> g1, SymGraph<TFunc, TADomain> g2, out int updateSize)
678 SymGraph<TFunc, TADomain> graph1 = g1;
679 SymGraph<TFunc, TADomain> graph2 = g2;
680 while (graph1 != graph2) {
683 if (graph2 == null) {
687 if (graph1.history_size > graph2.history_size)
688 graph1 = graph1.Parent;
689 else if (graph2.history_size > graph1.history_size)
690 graph2 = graph2.Parent;
692 graph1 = graph1.Parent;
693 graph2 = graph2.Parent;
696 SymGraph<TFunc, TADomain> tail = graph1;
697 int historySize = tail != null ? tail.history_size : 0;
698 updateSize = g1.history_size + g2.history_size - 2*historySize;
702 private static bool InternalLessEqual (SymGraph<TFunc, TADomain> thisG, SymGraph<TFunc, TADomain> thatG,
703 out IImmutableMap<SymValue, LispList<SymValue>> forward,
704 out IImmutableMap<SymValue, SymValue> backward)
707 SymGraph<TFunc, TADomain> commonTail = ComputeCommonTail (thisG, thatG, out updateSize);
708 if (thisG.IsImmutable)
709 thisG = thisG.Clone ();
711 var workList = new WorkList<EqualityPair<TFunc, TADomain>> ();
712 workList.Add (new EqualityPair<TFunc, TADomain> (thisG.const_root, thatG.const_root));
713 IImmutableSet<SymValue> backwardManifested = ImmutableSet<SymValue>.Empty (SymValue.GetUniqueKey);
714 IImmutableMap<SymValue, SymValue> backwardMap = ImmutableIntKeyMap<SymValue, SymValue>.Empty (SymValue.GetUniqueKey);
715 IImmutableMap<SymValue, LispList<SymValue>> forwardMap = ImmutableIntKeyMap<SymValue, LispList<SymValue>>.Empty (SymValue.GetUniqueKey);
716 IImmutableMap<SymValue, int> triggers = ImmutableIntKeyMap<SymValue, int>.Empty (SymValue.GetUniqueKey);
718 while (!workList.IsEmpty ()) {
719 EqualityPair<TFunc, TADomain> equalityPair = workList.Pull ();
720 SymValue sv1 = equalityPair.Sv1;
721 SymValue sv2 = equalityPair.Sv2;
724 if (VisitedBefore (sv2, backwardManifested, backwardMap, out s)) {
725 if (s != null && s == sv1)
728 if (DebugOptions.Debug)
729 Console.WriteLine ("---LessEqual fails due to pre-existing relation: {0} <- {1}", s, sv2);
735 TADomain val1 = sv1 == null ? thisG.UnderlyingTopValue.ForManifestedField () : thisG [sv1];
736 TADomain val2 = thatG [sv2];
737 if (!val1.LessEqual (val2)) {
738 if (DebugOptions.Debug)
739 Console.WriteLine ("---LessEqual fails due to abstract values: !({0} <= {1})", val1, val2);
745 backwardMap = backwardMap.Add (sv2, sv1);
746 forwardMap = forwardMap.Add (sv1, forwardMap [sv1].Cons (sv2));
748 backwardManifested = backwardManifested.Add (sv2);
749 if (thisG.HasAllBottomFields (sv1))
751 if (thatG.HasAllBottomFields (sv2)) {
752 if (DebugOptions.Debug)
754 Console.WriteLine ("---LessEqual fails due to bottom field difference");
761 foreach (TFunc function in thatG.Functions (sv2)) {
762 SymValue v1 = thisG [function, sv1];
763 SymValue v2 = thatG [function, sv2];
764 if (DebugOptions.Debug)
765 Console.WriteLine (" {0}-{1}->{2} <=? {3}-{4}->{5}", sv1, function, v1, sv2, function, v2);
766 workList.Add (new EqualityPair<TFunc, TADomain> (v1, v2));
769 foreach (var e in thatG.MultiEdges (sv2)) {
770 foreach (SymValue sv in thatG.MultiEdgeMap [sv2, e].AsEnumerable ()) {
771 if (!UpdateTrigger (sv, e, ref triggers))
774 SymGraphTerm<TFunc> term = thatG.EqualMultiTermsMap [sv];
775 var args = new SymValue[term.Args.Length];
776 for (int i = 0; i < args.Length; i++)
777 args [i] = backwardMap [term.Args [i]];
779 SymValue v1 = thisG.LookupWithoutManifesting (args, e.Function);
781 if (DebugOptions.Debug)
782 Console.WriteLine ("---LessEqual fails due to missing multi term {0}({1})",
784 string.Join (", ", term.Args.Select (it => it.ToString ())));
790 workList.Add (new EqualityPair<TFunc, TADomain> (v1, sv));
794 forward = forwardMap;
795 backward = CompleteWithCommon (backwardMap, thisG, commonTail.IdGenerator);
799 private static IImmutableMap<SymValue, SymValue> CompleteWithCommon (IImmutableMap<SymValue, SymValue> map,
800 SymGraph<TFunc, TADomain> thisGraph, int lastCommonId)
802 IEnumerable<SymValue> symValues = thisGraph.EqualTermsMap.Keys.Concat (thisGraph.EqualMultiTermsMap.Keys);
803 foreach (SymValue sv in symValues) {
804 if (IsCommon (sv, lastCommonId) && !map.ContainsKey (sv))
805 map = map.Add (sv, sv);
810 private static bool IsCommon (SymValue sv, int lastCommonId)
812 return sv.UniqueId <= lastCommonId;
815 private static bool UpdateTrigger (SymValue sv, MultiEdge<TFunc, TADomain> edge, ref IImmutableMap<SymValue, int> triggers)
817 int val = triggers [sv] + 1;
818 triggers = triggers.Add (sv, val);
819 return (val == edge.Arity);
822 private static bool VisitedBefore (SymValue sv2,
823 IImmutableSet<SymValue> backwardManifested,
824 IImmutableMap<SymValue, SymValue> backward,
827 sv1 = backward [sv2];
828 return sv1 != null || backwardManifested.Contains (sv2);
831 private bool IsSameEGraph (SymGraph<TFunc, TADomain> that)
835 if (that.Parent == this)
836 return that.Updates == Updates;
841 private void MarkAsImmutable ()
843 this.is_immutable = true;
846 #region Merge updates
847 private void AddUpdate (Update<TFunc, TADomain> update)
849 Updates = Updates.Cons (update);
852 private void AddAbstractValueUpdate (SymValue sv)
854 if (!IsOldSymbol (sv))
856 AddUpdate (new AbstractDomainUpdate<TFunc, TADomain> (sv));
859 private void AddEqualityUpdate (SymValue sv1, SymValue sv2)
861 if (!IsOldSymbol (sv1) || !IsOldSymbol (sv2))
863 AddUpdate (new EqualityUpdate<TFunc, TADomain> (sv1, sv2));
866 private void AddEdgeUpdate (SymValue from, TFunc function)
868 if (!IsOldSymbol (from))
870 AddUpdate (new EdgeUpdate<TFunc, TADomain> (from, function));
873 private void AddEliminateAllUpdate (SymValue from)
875 if (!IsOldSymbol (from))
877 foreach (TFunc function in TermMap.Keys2 (from))
878 AddUpdate (new EliminateEdgeUpdate<TFunc, TADomain> (from, function));
881 private void AddEliminateEdgeUpdate (SymValue from, TFunc function)
883 if (!IsOldSymbol (from))
885 AddUpdate (new EliminateEdgeUpdate<TFunc, TADomain> (from, function));
888 private void AddMultiEdgeUpdate (SymValue[] from, TFunc function)
890 for (int i = 0; i < from.Length; i++) {
891 if (!IsOldSymbol (from [i]))
895 AddUpdate (new MultiEdgeUpdate<TFunc, TADomain> (from, function));
899 public IImmutableMap<SymValue, LispList<SymValue>> GetForwardIdentityMap ()
901 var res = ImmutableIntKeyMap<SymValue, LispList<SymValue>>.Empty (SymValue.GetUniqueKey);
902 foreach (var sv in this.EqualTermsMap.Keys.Union (this.EqualMultiTermsMap.Keys)) {
903 res = res.Add (sv, LispList<SymValue>.Cons (sv, null));