public bool TryIntersect(CardRange r, out CardRange intersection) { var min = Cardinality.Max(lower, r.lower); var max = Cardinality.Min(upper, r.upper); if (max < min) { intersection = all; return(false); } else { intersection = new CardRange(min, max); return(true); } }
private bool Propagate(CardVar cvar) { Cardinality cd; CardRange lhs, rhs; CardRange intr, intrp; CardConstraint con; var stack = new Stack <CardConstraint>(); EnqueueConstraints(cvar, stack); while (stack.Count > 0) { con = stack.Pop(); lhs = GetRange(con.Lhs); rhs = Eval(con.Rhs); con.IsQueued = false; switch (con.Op) { case CardConstraint.OpKind.LEq: if ((cd = Cardinality.Min(lhs.Upper, rhs.Upper)) != lhs.Upper) { if (cd < lhs.Lower) { return(false); } UpdateRange(con.Lhs, lhs = new CardRange(lhs.Lower, cd)); EnqueueConstraints(con.Lhs, stack); } if (rhs.Lower < lhs.Lower) { foreach (var rhsvar in con.RhsVars) { rhs = GetRange(rhsvar); if (Eval(con.Rhs, rhsvar, rhs.Lower, false) >= lhs.Lower) { continue; } intr = new CardRange(rhs.Lower, Cardinality.Min(lhs.Lower, rhs.Upper)); while (intr.Lower + 1 < intr.Upper) { intrp = intr.Bisect(true); if (Eval(con.Rhs, rhsvar, intrp.Lower, false) >= lhs.Lower) { intr = new CardRange(intr.Lower, intrp.Lower); } else { intr = new CardRange(intrp.Lower, intr.Upper); } } if (Eval(con.Rhs, rhsvar, intr.Lower, false) >= lhs.Lower) { if (intr.Lower > rhs.Lower) { UpdateRange(rhsvar, new CardRange(intr.Lower, rhs.Upper)); EnqueueConstraints(rhsvar, stack); continue; } } else if (Eval(con.Rhs, rhsvar, intr.Upper, false) >= lhs.Lower) { if (intr.Upper > rhs.Lower) { UpdateRange(rhsvar, new CardRange(intr.Upper, rhs.Upper)); EnqueueConstraints(rhsvar, stack); continue; } } else { return(false); } } } break; case CardConstraint.OpKind.GEq: if ((cd = Cardinality.Max(lhs.Lower, rhs.Lower)) != lhs.Lower) { if (cd > lhs.Upper) { return(false); } UpdateRange(con.Lhs, lhs = new CardRange(cd, lhs.Upper)); EnqueueConstraints(con.Lhs, stack); } if (rhs.Upper > lhs.Upper) { foreach (var rhsvar in con.RhsVars) { rhs = GetRange(rhsvar); if (Eval(con.Rhs, rhsvar, rhs.Upper, true) <= lhs.Upper) { continue; } intr = new CardRange(rhs.Lower, Cardinality.Min(rhs.Upper, lhs.Upper)); while (intr.Lower + 1 < intr.Upper) { intrp = intr.Bisect(false); if (Eval(con.Rhs, rhsvar, intrp.Upper, true) <= lhs.Upper) { intr = new CardRange(intrp.Upper, intr.Upper); } else { intr = new CardRange(intr.Lower, intrp.Upper); } } if (Eval(con.Rhs, rhsvar, intr.Upper, true) <= lhs.Upper) { if (intr.Upper < rhs.Upper) { UpdateRange(rhsvar, new CardRange(rhs.Lower, intr.Upper)); EnqueueConstraints(rhsvar, stack); continue; } } else if (Eval(con.Rhs, rhsvar, intr.Lower, true) <= lhs.Upper) { if (intr.Lower < rhs.Upper) { UpdateRange(rhsvar, new CardRange(rhs.Lower, intr.Lower)); EnqueueConstraints(rhsvar, stack); continue; } } else { return(false); } } } break; default: throw new NotImplementedException(); } } return(true); }