/* Utility functions for working with arrays of integers 
 * Mostly specification functions, but swap is effectful
 * 
 * 15-122 Principles of Imperative Computation */


/*** Interface ***/

/* is_in: x in A[lo,hi) */
bool is_in(int x, int[] A, int lo, int hi)
/*@requires 0 <= lo  && lo <= hi && hi <= \length(A); @*/ ;

/* is_sorted: A[lo,hi) SORTED */
bool is_sorted(int[] A, int lo, int hi)
/*@requires 0 <= lo  && lo <= hi && hi <= \length(A); @*/ ;

/* swap(A, i, j) has the effect of switching A[i] and A[j] */
void swap(int[] A, int i, int j)
/*@ requires 0 <= i && i < \length(A) && 0 <= j && j < \length(A); @*/ ;


/* gt_seg: x > A[lo,hi) */
bool gt_seg(int x, int[] A, int lo, int hi)
/*@requires 0 <= lo && lo <= hi && hi <= \length(A); @*/ ;

/* ge_seg: x >= A[lo,hi) */
bool ge_seg(int x, int[] A, int lo, int hi)
/*@requires 0 <= lo && lo <= hi && hi <= \length(A); @*/ ;

/* lt_seg: x < A[lo,hi) */
bool lt_seg(int x, int[] A, int lo, int hi)
/*@requires 0 <= lo && lo <= hi && hi <= \length(A); @*/ ;

/* le_seg: x <= A[lo,hi) */
bool le_seg(int x, int[] A, int lo, int hi)
/*@requires 0 <= lo && lo <= hi && hi <= \length(A); @*/ ;


/* gt_segs: A[lo1,hi1) > B[lo2,hi2) */
bool gt_segs(int[] A, int lo1, int hi1, int[] B, int lo2, int hi2)
/*@requires 0 <= lo1 && lo1 <= hi1 && hi1 <= \length(A); @*/ 
/*@requires 0 <= lo2 && lo2 <= hi2 && hi2 <= \length(B); @*/ ;

/* ge_segs: A[lo1,hi1) >= B[lo2,hi2) */
bool ge_segs(int[] A, int lo1, int hi1, int[] B, int lo2, int hi2)
/*@requires 0 <= lo1 && lo1 <= hi1 && hi1 <= \length(A); @*/ 
/*@requires 0 <= lo2 && lo2 <= hi2 && hi2 <= \length(B); @*/ ;

/* lt_segs: A[lo1,hi1) < B[lo2,hi2) */
bool lt_segs(int[] A, int lo1, int hi1, int[] B, int lo2, int hi2)
/*@requires 0 <= lo1 && lo1 <= hi1 && hi1 <= \length(A); @*/ 
/*@requires 0 <= lo2 && lo2 <= hi2 && hi2 <= \length(B); @*/ ;

/* le_segs: A[lo1,hi1) <= B[lo2,hi2) */
bool le_segs(int[] A, int lo1, int hi1, int[] B, int lo2, int hi2)
/*@requires 0 <= lo1 && lo1 <= hi1 && hi1 <= \length(A); @*/ 
/*@requires 0 <= lo2 && lo2 <= hi2 && hi2 <= \length(B); @*/ ;


/*** Implementation ***/

bool is_in(int x, int[] A, int lo, int hi)
/*@requires 0 <= lo 
         && lo <= hi 
         && hi <= \length(A); @*/
{
  if (lo == hi) return false;
  return A[lo] == x || is_in(x,A,lo+1,hi);
}

void swap(int[] A, int i, int j)
//@requires 0 <= i && i < \length(A);
//@requires 0 <= j && j < \length(A);
{
  int tmp = A[i];
  A[i] = A[j];
  A[j] = tmp;
}

bool gt_seg(int x, int[] A, int lo, int hi) 
/*@requires 0 <= lo 
         && lo <= hi 
         && hi <= \length(A); @*/
{
  if (lo == hi) return true;
  return x > A[lo] && gt_seg(x, A, lo+1, hi);
}

bool ge_seg(int x, int[] A, int lo, int hi) 
/*@requires 0 <= lo 
         && lo <= hi 
         && hi <= \length(A); @*/
{
  if (lo == hi) return true;
  return x >= A[lo] && ge_seg(x, A, lo+1, hi);
}

bool lt_seg(int x, int[] A, int lo, int hi) 
/*@requires 0 <= lo 
         && lo <= hi 
         && hi <= \length(A); @*/
{
  if (lo == hi) return true;
  return x < A[lo] && lt_seg(x, A, lo+1, hi);
}

bool le_seg(int x, int[] A, int lo, int hi) 
/*@requires 0 <= lo 
         && lo <= hi 
         && hi <= \length(A); @*/
{
  if (lo == hi) return true;
  return x <= A[lo] && le_seg(x, A, lo+1, hi);
}

bool is_sorted(int[] A, 
               int lo, 
               int hi)
/*@requires 0 <= lo 
         && lo <= hi 
         && hi <= \length(A); @*/
{
  if (lo == hi) return true;
  return le_seg(A[lo], A, lo+1, hi) && is_sorted(A, lo+1, hi);
}

bool gt_segs(int[] A, int lo1, int hi1, int[] B, int lo2, int hi2)
//@requires 0 <= lo1 && lo1 <= hi1 && hi1 <= \length(A);
//@requires 0 <= lo2 && lo2 <= hi2 && hi2 <= \length(B);
{
  if (lo1 == hi1) return true;
  return gt_seg(A[lo1], B, lo2, hi2) 
    && gt_segs(A, lo1+1, hi1, B, lo2, hi2);
}

bool ge_segs(int[] A, int lo1, int hi1, int[] B, int lo2, int hi2)
//@requires 0 <= lo1 && lo1 <= hi1 && hi1 <= \length(A);
//@requires 0 <= lo2 && lo2 <= hi2 && hi2 <= \length(B);
{
  if (lo1 == hi1) return true;
  return ge_seg(A[lo1], B, lo2, hi2) 
    && ge_segs(A, lo1+1, hi1, B, lo2, hi2);
}

bool lt_segs(int[] A, int lo1, int hi1, int[] B, int lo2, int hi2)
//@requires 0 <= lo1 && lo1 <= hi1 && hi1 <= \length(A);
//@requires 0 <= lo2 && lo2 <= hi2 && hi2 <= \length(B);
{
  if (lo1 == hi1) return true;
  return lt_seg(A[lo1], B, lo2, hi2) 
    && lt_segs(A, lo1+1, hi1, B, lo2, hi2);
}

bool le_segs(int[] A, int lo1, int hi1, int[] B, int lo2, int hi2)
//@requires 0 <= lo1 && lo1 <= hi1 && hi1 <= \length(A);
//@requires 0 <= lo2 && lo2 <= hi2 && hi2 <= \length(B);
{
  if (lo1 == hi1) return true;
  return le_seg(A[lo1], B, lo2, hi2) 
    && le_segs(A, lo1+1, hi1, B, lo2, hi2);
}