/// <summary>
    /// Uses the frame to simplify Constraints.  See section 3.3.1.2 of Cousot and Halbwachs.
    /// 
    /// Note:  This code does not necessarily eliminate all irrelevant equalities; Cousot and
    /// Halbwachs only claim that the technique eliminates all irrelevant inequalities.
    /// </summary>
    void SimplifyConstraints() {
      if (Constraints == null) {
        return;
      }
      Contract.Assume(this.FrameVertices != null);
      Contract.Assume(this.FrameRays != null);

      SimplificationStatus[] status = new SimplificationStatus[Constraints.Count];
      /*readonly*/
      int feCount = FrameVertices.Count + FrameRays.Count;

      // Create a table that keeps track of which constraints are satisfied by which vertices and rays
      bool[,] sat = new bool[Constraints.Count, FrameVertices.Count + FrameRays.Count];
      for (int i = 0; i < Constraints.Count; i++) {
        status[i] = SimplificationStatus.Relevant;
        LinearConstraint lc = (LinearConstraint/*!*/)cce.NonNull(Constraints[i]);
        int cnt = 0;  // number of vertices and rays that saturate lc
        for (int j = 0; j < FrameVertices.Count; j++) {
          FrameElement vertex = (FrameElement/*!*/)cce.NonNull(FrameVertices[j]);
          if (lc.IsSaturatedBy(vertex, true)) {
            sat[i, j] = true;
            cnt++;
          }
        }
        if (cnt == 0) {
          // no vertex saturates the constraint, so the constraint is irrelevant
          status[i] = SimplificationStatus.Irrelevant;
          continue;
        }
        for (int j = 0; j < FrameRays.Count; j++) {
          FrameElement ray = (FrameElement/*!*/)cce.NonNull(FrameRays[j]);
          if (lc.IsSaturatedBy(ray, false)) {
            sat[i, FrameVertices.Count + j] = true;
            cnt++;
          }
        }
        if (cnt == feCount) {
          status[i] = SimplificationStatus.More;
        } else {
          // Cousot and Halbwachs says that all equalities are found in the way we just tested.
          // If I understand that right, then we should not get here if the constraint is an
          // equality constraint.  The following assertion tests my understanding.  --KRML
          System.Diagnostics.Debug.Assert(lc.Relation == LinearConstraint.ConstraintRelation.LE);
        }
      }

      CheckPairSimplifications(sat, status);

      // Finally, make the changes to the list of constraints
      for (int i = Constraints.Count - 1; 0 <= i; i--) {
        switch (status[i]) {
          case SimplificationStatus.Relevant:
            break;
          case SimplificationStatus.Irrelevant:
#if DEBUG_PRINT
            Console.WriteLine("Removing irrelevant constraint: {0}", Constraints[i]);
#endif
            Constraints.RemoveAt(i);
            break;
          case SimplificationStatus.More:
            LinearConstraint lc = (LinearConstraint/*!*/)cce.NonNull(Constraints[i]);
            if (lc.Relation == LinearConstraint.ConstraintRelation.LE) {
#if DEBUG_PRINT
              Console.WriteLine("Converting the following constraint into an equality: {0}", lc);
#endif
              LinearConstraint lcEq = lc.ChangeRelation(LinearConstraint.ConstraintRelation.EQ);
              Constraints[i] = lcEq;
            }
            break;
        }
      }

      foreach (LinearConstraint/*!*/ lc in Constraints) {
        Contract.Assert(lc != null);
        lc.Normalize();
      }
    }
    /// <summary>
    /// Requires sat.GetLength(0) == status.Length.
    /// </summary>
    /// <param name="sat"></param>
    /// <param name="status"></param>
    static void CheckPairSimplifications(bool[,]/*!*/ sat, SimplificationStatus[]/*!*/ status) {
      Contract.Requires(status != null);
      Contract.Requires(sat != null);
      Contract.Requires(sat.GetLength(0) == status.Length);
      int M = sat.GetLength(0);
      int N = sat.GetLength(1);

      for (int i = 0; i < M - 1; i++) {
        if (status[i] != SimplificationStatus.Relevant) {
          continue;
        }
        for (int j = i + 1; j < M; j++) {
          if (status[j] != SimplificationStatus.Relevant) {
            continue;
          }
          // check (sat[i,*] <= sat[j,*]) and (sat[i,*] >= sat[j,*])
          int cmp = 0;  // -1: (sat[i,*] <= sat[j,*]),  0: equal,  1: (sat[i,*] >= sat[j,*])
          for (int c = 0; c < N; c++) {
            if (cmp < 0) {
              if (sat[i, c] && !sat[j, c]) {
                // incomparable
                goto NEXT_PAIR;
              }
            } else if (0 < cmp) {
              if (!sat[i, c] && sat[j, c]) {
                // incomparable
                goto NEXT_PAIR;
              }
            } else if (sat[i, c] != sat[j, c]) {
              if (!sat[i, c]) {
                cmp = -1;
              } else {
                cmp = 1;
              }
            }
          }
          if (cmp <= 0) {
            // sat[i,*] <= sat[j,*] holds, so mark i as irrelevant
            status[i] = SimplificationStatus.Irrelevant;
            goto NEXT_OUTER;
          } else {
            // sat[i,*] >= sat[j,*] holds, so mark j as irrelevant
            status[j] = SimplificationStatus.Irrelevant;
          }
        NEXT_PAIR: {
          }
        }
      NEXT_OUTER: {
        }
      }
    }
    static void RemoveIrrelevantFrameElements(ArrayList/*!*/ /*FrameElement*/ ff, SimplificationStatus[]/*!*/ status,
      /*maybe null*/ ArrayList /*FrameElement*/ lines) {
      Contract.Requires(ff != null);
      Contract.Requires(status != null);
      Contract.Requires(ff.Count == status.Length);
      for (int j = ff.Count - 1; 0 <= j; j--) {
        switch (status[j]) {
          case SimplificationStatus.Relevant:
            break;
          case SimplificationStatus.Irrelevant:
#if DEBUG_PRINT
            Console.WriteLine("Removing irrelevant {0}: {1}", lines == null ? "vertex" : "ray", ff[j]);
#endif
            ff.RemoveAt(j);
            break;
          case SimplificationStatus.More:
            System.Diagnostics.Debug.Assert(lines != null);
            FrameElement f = (FrameElement)ff[j];
#if DEBUG_PRINT
            Console.WriteLine("Changing ray into line: {0}", f);
#endif
            ff.RemoveAt(j);
            Contract.Assert(lines != null);
            lines.Add(f);
            break;
        }
      }
    }
    /// <summary>
    /// For each i, sets status[i] to:
    ///  <ul>
    ///  <li>Irrelevant if ff[i] is irrelevant</li>
    ///  <li>Relevant if ff[i] is irrelevant</li>
    ///  <li>More if vertices is true and ray ff[i] can be replaced by a line ff[i]</li>
    ///  </ul>
    /// </summary>
    /// <param name="ff"></param>
    /// <param name="vertices">true if "ff" contains vertices; false if "ff" contains rays</param>
    /// <param name="constraints"></param>
    /// <param name="status"></param>
    static void SimplifyFrameElements(ArrayList/*!*/ /*FrameElement*/ ff, bool vertices, ArrayList/*!*/ /*LinearConstraint*/ constraints, out SimplificationStatus[]/*!*/ status) {
      Contract.Requires(ff != null);
      Contract.Requires(constraints != null);
      Contract.Ensures(Contract.ValueAtReturn(out status) != null);
      status = new SimplificationStatus[ff.Count];
      bool[,] sat = new bool[ff.Count, constraints.Count];
      for (int i = 0; i < ff.Count; i++) {
        FrameElement f = (FrameElement/*!*/)cce.NonNull(ff[i]);
        int cnt = 0;
        for (int c = 0; c < constraints.Count; c++) {
          LinearConstraint lc = (LinearConstraint/*!*/)cce.NonNull(constraints[c]);
          bool s = lc.IsSaturatedBy(f, vertices);
          if (s) {
            sat[i, c] = true;
            cnt++;
          }
        }
        if (!vertices && cnt == constraints.Count) {
          status[i] = SimplificationStatus.More;
        } else {
          status[i] = SimplificationStatus.Relevant;
        }
      }

      CheckPairSimplifications(sat, status);
    }