private void Add(Term t) { if (t.Symbol == unnSymb) { return; } bool wasAdded; Set <Term> bin; switch (t.Symbol.Kind) { case SymbolKind.ConSymb: case SymbolKind.MapSymb: { if (!binMap.TryFindValue(t.Symbol, out bin)) { bin = new Set <Term>(Term.Compare); binMap.Add(t.Symbol, bin); } Term max = null; if (t.Symbol.Kind == SymbolKind.ConSymb) { max = index.MkApply(((ConSymb)t.Symbol).SortSymbol, TermIndex.EmptyArgs, out wasAdded); } else { max = index.MkApply(((MapSymb)t.Symbol).SortSymbol, TermIndex.EmptyArgs, out wasAdded); } if (bin.Contains(max)) { return; } else { bin.Add(t); } break; } case SymbolKind.UserSortSymb: { if (!binMap.TryFindValue(((UserSortSymb)t.Symbol).DataSymbol, out bin)) { bin = new Set <Term>(Term.Compare); binMap.Add(((UserSortSymb)t.Symbol).DataSymbol, bin); bin.Add(t); } else if (!bin.Contains(t)) { bin.Clear(); bin.Add(t); } break; } case SymbolKind.UserCnstSymb: { Contract.Assert(t.Symbol.IsNonVarConstant); if (!binMap.TryFindValue(trueSymb, out bin)) { bin = new Set <Term>(Term.Compare); binMap.Add(trueSymb, bin); } bin.Add(t); break; } case SymbolKind.BaseSortSymb: { var baseSort = ((BaseSortSymb)t.Symbol); var binName = baseSort.SortKind == BaseSortKind.String ? stringSymb : realSymb; if (!binMap.TryFindValue(binName, out bin)) { bin = new Set <Term>(Term.Compare); binMap.Add(binName, bin); } switch (baseSort.SortKind) { case BaseSortKind.String: if (!bin.Contains(t)) { bin.Clear(); bin.Add(t); } break; case BaseSortKind.Real: if (!bin.Contains(t)) { bin.Clear(); bin.Add(t); intervals = null; } break; case BaseSortKind.Integer: if (!bin.Contains(t) && !bin.Contains(index.MkApply(realSymb, TermIndex.EmptyArgs, out wasAdded))) { bin.Remove(index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.Natural), TermIndex.EmptyArgs, out wasAdded)); bin.Remove(index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.PosInteger), TermIndex.EmptyArgs, out wasAdded)); bin.Remove(index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.NegInteger), TermIndex.EmptyArgs, out wasAdded)); bin.Add(t); intervals = null; } break; case BaseSortKind.Natural: if (!bin.Contains(t) && !bin.Contains(index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.Integer), TermIndex.EmptyArgs, out wasAdded)) && !bin.Contains(index.MkApply(realSymb, TermIndex.EmptyArgs, out wasAdded))) { bin.Remove(index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.PosInteger), TermIndex.EmptyArgs, out wasAdded)); bin.Add(t); if (intervals != null && intervals.Count > 0) { BigInteger min, max; intervals.GetExtrema(out min, out max); intervals.Remove(BigInteger.Zero, BigInteger.Max(BigInteger.Zero, max)); } } break; case BaseSortKind.PosInteger: if (!bin.Contains(t) && !bin.Contains(index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.Natural), TermIndex.EmptyArgs, out wasAdded)) && !bin.Contains(index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.Integer), TermIndex.EmptyArgs, out wasAdded)) && !bin.Contains(index.MkApply(realSymb, TermIndex.EmptyArgs, out wasAdded))) { bin.Add(t); if (intervals != null && intervals.Count > 0) { BigInteger min, max; intervals.GetExtrema(out min, out max); intervals.Remove(BigInteger.One, BigInteger.Max(BigInteger.One, max)); } } break; case BaseSortKind.NegInteger: if (!bin.Contains(t) && !bin.Contains(index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.Integer), TermIndex.EmptyArgs, out wasAdded)) && !bin.Contains(index.MkApply(realSymb, TermIndex.EmptyArgs, out wasAdded))) { bin.Add(t); if (intervals != null && intervals.Count > 0) { BigInteger min, max; intervals.GetExtrema(out min, out max); intervals.Remove(BigInteger.Min(min, BigInteger.MinusOne), BigInteger.MinusOne); } } break; default: throw new NotImplementedException(); } break; } case SymbolKind.BaseCnstSymb: { var baseCnst = (BaseCnstSymb)t.Symbol; var binName = baseCnst.CnstKind == CnstKind.String ? stringSymb : realSymb; if (!binMap.TryFindValue(binName, out bin)) { bin = new Set <Term>(Term.Compare); binMap.Add(binName, bin); } switch (baseCnst.CnstKind) { case CnstKind.String: if (!bin.Contains(index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.String), TermIndex.EmptyArgs, out wasAdded))) { bin.Add(t); } break; case CnstKind.Numeric: { var rat = (Rational)baseCnst.Raw; if (bin.Contains(index.MkApply(realSymb, TermIndex.EmptyArgs, out wasAdded))) { } else if (!rat.IsInteger) { bin.Add(t); } else if (bin.Contains(index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.Integer), TermIndex.EmptyArgs, out wasAdded))) { } else if (rat.Sign < 0) { if (!bin.Contains(index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.NegInteger), TermIndex.EmptyArgs, out wasAdded))) { intervals = intervals == null ? new IntIntervals() : intervals; intervals.Add(rat.Numerator, rat.Numerator); } } else if (rat.Sign == 0) { if (!bin.Contains(index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.Natural), TermIndex.EmptyArgs, out wasAdded))) { intervals = intervals == null ? new IntIntervals() : intervals; intervals.Add(rat.Numerator, rat.Numerator); } } else { if (!bin.Contains(index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.Natural), TermIndex.EmptyArgs, out wasAdded)) && !bin.Contains(index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.PosInteger), TermIndex.EmptyArgs, out wasAdded))) { intervals = intervals == null ? new IntIntervals() : intervals; intervals.Add(rat.Numerator, rat.Numerator); } } break; } default: throw new NotImplementedException(); } break; } case SymbolKind.BaseOpSymb: { Contract.Assert(t.Symbol == rngSymb); if (!binMap.TryFindValue(realSymb, out bin)) { bin = new Set <Term>(Term.Compare); binMap.Add(realSymb, bin); } if (!bin.Contains(index.MkApply(realSymb, TermIndex.EmptyArgs, out wasAdded)) && !bin.Contains(index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.Integer), TermIndex.EmptyArgs, out wasAdded))) { var end1 = ((Rational)((BaseCnstSymb)t.Args[0].Symbol).Raw).Numerator; var end2 = ((Rational)((BaseCnstSymb)t.Args[1].Symbol).Raw).Numerator; intervals = intervals == null ? new IntIntervals() : intervals; intervals.Add(end1, end2); BigInteger min, max; intervals.GetExtrema(out min, out max); if (bin.Contains(index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.Natural), TermIndex.EmptyArgs, out wasAdded))) { intervals.Remove(BigInteger.Zero, BigInteger.Max(BigInteger.Zero, max)); } else if (bin.Contains(index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.PosInteger), TermIndex.EmptyArgs, out wasAdded))) { intervals.Remove(BigInteger.One, BigInteger.Max(BigInteger.One, max)); } if (bin.Contains(index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.NegInteger), TermIndex.EmptyArgs, out wasAdded))) { intervals.Remove(BigInteger.Min(BigInteger.MinusOne, min), BigInteger.MinusOne); } } break; } default: throw new InvalidOperationException(); } }
private void IntersectNumerics(Set <Term> s1, IntIntervals i1, Set <Term> s2, IntIntervals i2, BinnedUnion result) { bool wasAdded; var realTrm = index.MkApply(realSymb, TermIndex.EmptyArgs, out wasAdded); var intTrm = index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.Integer), TermIndex.EmptyArgs, out wasAdded); var natTrm = index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.Natural), TermIndex.EmptyArgs, out wasAdded); var posTrm = index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.PosInteger), TermIndex.EmptyArgs, out wasAdded); var negTrm = index.MkApply(index.SymbolTable.GetSortSymbol(BaseSortKind.NegInteger), TermIndex.EmptyArgs, out wasAdded); //// Handle the case where one side contains Real if (s1.Contains(realTrm)) { foreach (var t in s2) { result.Add(t); } if (i2 != null) { foreach (var kv in i2.CanonicalForm) { result.Add(index.MkApply( rngSymb, new Term[] { index.MkCnst(new Rational(kv.Key, BigInteger.One), out wasAdded), index.MkCnst(new Rational(kv.Value, BigInteger.One), out wasAdded) }, out wasAdded)); } } return; } else if (s2.Contains(realTrm)) { foreach (var t in s1) { result.Add(t); } if (i1 != null) { foreach (var kv in i1.CanonicalForm) { result.Add(index.MkApply( rngSymb, new Term[] { index.MkCnst(new Rational(kv.Key, BigInteger.One), out wasAdded), index.MkCnst(new Rational(kv.Value, BigInteger.One), out wasAdded) }, out wasAdded)); } } return; } else { //// Need to keep all real constants common to both sets. var sA = s1.Count <= s2.Count ? s1 : s2; var sB = s2.Count >= s1.Count ? s2 : s1; foreach (var t in sA) { if (t.Symbol.Kind == SymbolKind.BaseCnstSymb && sB.Contains(t)) { result.Add(t); } } } //// Handle the case where one side contains Integer. if (s1.Contains(intTrm)) { foreach (var t in s2) { if (t.Symbol.Kind != SymbolKind.BaseCnstSymb || s1.Contains(t)) { result.Add(t); } } if (i2 != null) { foreach (var kv in i2.CanonicalForm) { result.Add(index.MkApply( rngSymb, new Term[] { index.MkCnst(new Rational(kv.Key, BigInteger.One), out wasAdded), index.MkCnst(new Rational(kv.Value, BigInteger.One), out wasAdded) }, out wasAdded)); } } return; } else if (s2.Contains(intTrm)) { foreach (var t in s1) { if (t.Symbol.Kind != SymbolKind.BaseCnstSymb || s2.Contains(t)) { result.Add(t); } result.Add(t); } if (i1 != null) { foreach (var kv in i1.CanonicalForm) { result.Add(index.MkApply( rngSymb, new Term[] { index.MkCnst(new Rational(kv.Key, BigInteger.One), out wasAdded), index.MkCnst(new Rational(kv.Value, BigInteger.One), out wasAdded) }, out wasAdded)); } } return; } //// Neither set contains all reals or all integers. //// First take intersections of intervals: O(n) if (i1 != null && i2 != null) { BigInteger aS, aE, bS, bE, s, e; using (var itA = i1.CanonicalForm.GetEnumerator()) { using (var itB = i2.CanonicalForm.GetEnumerator()) { var cont = itA.MoveNext() && itB.MoveNext(); while (cont) { aS = itA.Current.Key; aE = itA.Current.Value; bS = itB.Current.Key; bE = itB.Current.Value; s = aS > bS ? aS : bS; e = aE < bE ? aE : bE; cont = aE <= bE?itA.MoveNext() : itB.MoveNext(); if (s <= e) { result.Add(index.MkApply( rngSymb, new Term[] { index.MkCnst(new Rational(s, BigInteger.One), out wasAdded), index.MkCnst(new Rational(e, BigInteger.One), out wasAdded) }, out wasAdded)); } } } } } //// Next consider intervals intersecting with Nat, Pos, and Neg. if (i2 != null) { bool hasNat = s1.Contains(natTrm); bool hasPos = s1.Contains(posTrm); bool hasNeg = s1.Contains(negTrm); if (hasNat || hasPos || hasNeg) { var nonNegLB = hasNat ? BigInteger.Zero : BigInteger.One; foreach (var kv in i2.CanonicalForm) { if (hasNeg) { if (kv.Key < BigInteger.Zero) { result.Add(index.MkApply( rngSymb, new Term[] { index.MkCnst(new Rational(kv.Key, BigInteger.One), out wasAdded), index.MkCnst(new Rational(BigInteger.Min(kv.Value, BigInteger.MinusOne), BigInteger.One), out wasAdded) }, out wasAdded)); } } if (hasNat || hasPos) { if (kv.Value >= nonNegLB) { result.Add(index.MkApply( rngSymb, new Term[] { index.MkCnst(new Rational(BigInteger.Max(kv.Key, nonNegLB), BigInteger.One), out wasAdded), index.MkCnst(new Rational(kv.Value, BigInteger.One), out wasAdded) }, out wasAdded)); } } } } } if (i1 != null) { bool hasNat = s2.Contains(natTrm); bool hasPos = s2.Contains(posTrm); bool hasNeg = s2.Contains(negTrm); if (hasNat || hasPos || hasNeg) { var nonNegLB = hasNat ? BigInteger.Zero : BigInteger.One; foreach (var kv in i1.CanonicalForm) { if (hasNeg) { if (kv.Key < BigInteger.Zero) { result.Add(index.MkApply( rngSymb, new Term[] { index.MkCnst(new Rational(kv.Key, BigInteger.One), out wasAdded), index.MkCnst(new Rational(BigInteger.Min(kv.Value, BigInteger.MinusOne), BigInteger.One), out wasAdded) }, out wasAdded)); } } if (hasNat || hasPos) { if (kv.Value >= nonNegLB) { result.Add(index.MkApply( rngSymb, new Term[] { index.MkCnst(new Rational(BigInteger.Max(kv.Key, nonNegLB), BigInteger.One), out wasAdded), index.MkCnst(new Rational(kv.Value, BigInteger.One), out wasAdded) }, out wasAdded)); } } } } } //// Finally, consider intersections between the sorts Nat, Pos, Neg. if (s1.Contains(natTrm)) { if (s2.Contains(natTrm)) { result.Add(natTrm); } else if (s2.Contains(posTrm)) { result.Add(posTrm); } } else if (s2.Contains(natTrm)) { if (s1.Contains(natTrm)) { result.Add(natTrm); } else if (s1.Contains(posTrm)) { result.Add(posTrm); } } else if (s1.Contains(posTrm) && s2.Contains(posTrm)) { result.Add(posTrm); } if (s1.Contains(negTrm) && s2.Contains(negTrm)) { result.Add(negTrm); } }