

int allZero(int * A, int len) {
  /* Note in theory one must assert here that A + (0..len-1) are valid pointers.
     There is no good way in CIVL-C to express it currently.
  */
  $assert($true);
  
  int ret;
  $havoc(&ret); // assigning ret a fresh symbolic constant
  $assume(ret == 0 || ret == 1);
  $assume(ret == 1 => $forall (int i: 0 .. (len-1)) A[i] == 0);
  $assume(ret == 0 => $exists (int i: 0 .. (len-1)) A[i] != 0);
  return ret;
}


int allZeroImpl(int * A, int len) {
  int ret = 1;
  
  for (int i = 0; i < len; i++) {
    if (A[i] != 0) {
      ret = 0;
      // return ret // I comment out this early return to enlarge the state space of this function 
                    // for a model checker
    }
  }
  return ret;
}

#define N 10
$input int A[N];

int main() {
  int ret;
  
  /* These two calls deliver the same functionality for the assertion
     below.  The first call is much faster when N is large. But one
     has to prove that allZero is an abstraction of allZeroImpl.

     A separate proof can be done with smaller scopes or using loop
     invariants.  In either case, it can overcome the state explosion
     problem brought by nondeterminism when N is very large.
  */
  ret = allZero(A, N);             
  //ret = allZeroImpl(A, N); 
  
  $assert(ret == 1 => $forall (int i: 0 .. N-1) A[i] == 0);  
}


