Explanation:
I've following problem statement at hand, I came across an interesting 2 liner, C solution for it under leedcode discussion section. I tried to decompose it to understand what it means, and except one small line, I understood the rest. My question is at the end.
Leetcode Problem Statement:
Given an array arr of positive integers sorted in a strictly increasing order, and an integer k.
Find the kth positive integer that is missing from this array.
Example 1: Input: arr = [2,3,4,7,11], k = 5
Output: 9
Explanation: The missing positive integers are
[1,5,6,8,9,10,12,13,...]. The 5th missing >>positive integer is 9.
Example 2:
Input: arr = [1,2,3,4], k = 2
Output: 6
Explanation: The missing positive integers are [5,6,7,...].
The 2nd missing positive integer is 6.
Constraints:
1 <= arr.length <= 1000
1 <= arr[i] <= 1000
1 <= k <= 1000
arr[i] < arr[j] for 1 <= i < j <= arr.length
Two liner C solution:
int findKthPositive(int* arr, int arrSize, int k){
for (int arrCurrIndex = 0, counter = 1 ; (k && (arrCurrIndex < arrSize) ? ((arr[arrCurrIndex] != counter) ? k-- : ++arrCurrIndex) : k--) || (k = counter-1, 0) ; counter++);
return k;
}
For reference: Following is a similar algorithm that's being deployed, but its just cleaner to understand.
int findKthPositive(int* arr, int arrSize, int k){
for (int counter=1, arrCurrIndex=0; counter<10000; counter++) {
// exceed arr limits
if (arrCurrIndex < arrSize) {
if (counter == arr[arrCurrIndex]) { // found element in array
index++;
continue;
}
}
// missing element
k--;
if (k==0) {
return counter;
}
}
return 0;
}
My question:
What does following line in solution #1 means exactly?
(k = counter-1, 0)
======UPDATE ON ANSWER=======
I modified solution #1 in question slightly to make it more readable. It highlights what is going on with the given statement in question.
Here is the modified solution:
int findKthPositive(int* arr, int arrSize, int k){
// move counter out of the foor loop
int counter=1;
for (int arrCurrIndex = 0;
(k && (arrCurrIndex < arrSize) ?
((arr[arrCurrIndex] != counter) ? k-- : ++arrCurrIndex)
: k--); counter++);
return counter-1;
}
The binary comma operator , evaluates the first operand, discards the result and then evaluates the second one.
In the expression you posted we have
... || (k = counter-1, 0) ;
so counter-1 is actually assigned to k but its evaluation (k itself) is discarded so that 0 is used. Why 0? Because it is the neutral operand for logic or operator ||. In fact
X || 0 ==> X
In other words we have the expression
stuff_at_the_left || (k = counter-1, 0 )
that is evaluated as
stuff_at_the_left || 0
And since 0 is the neutral operand in logical or, the final evaluation is stuff_at_the_left.
The purpose of this weird expression is to cheat: the author at some point needed to assign that value to k but without adding more lines "ruining" the one liner. So they included the assignment in the logical expression making it neutral with comma operator combined with or operator's neutral operand.We also have to say that the assignment k=counter-1, 0 is performed only if all stuff_at_the_left is evaluated as 0 (due to the short circuiting nature of logical operators in C). The resulting expanded code is
if (!stuff_at_the_left)
k= counter-1;
Note: the comma operator has the lowest precedence among all the operators in C, and that's why the assignment is performed at first.
I need to check whether the elements on the main diagonal of a matrix are even and divisible into sum of its indexes. I remembered such elements in an 1-D array:
for (i=0; i<n; ++i)
for (j=0; j<m; ++j)
{
if ((i == j) && ((arr[i][j] % 2) == 0))
{
arr2[count] = arr[i][j];
++count;
break;
}
}
Then I replace the elements which satisfy the condition with the sum of its indexes and place a special condition for [0][0] because of dividing on 0:
count = 0;
for (i=0; i<n; ++i)
for (j=0; j<m; ++j)
{
if ((i+j != 0) && (arr[i][j] == arr2[count]) && ((arr[i][j] % (i+j)) == 0))
{
arr[i][j] = i+j;
++count;
}
else if (((i+j) == 0) && (arr[i][j] == arr2[count])) arr[i][j] = 0;
}
The trouble is that when the first element is even, it is the only replaced number, and the condition doesn't work for the other elements:
Problem:
arr2 is not filled appropriately. As soon as you fill one element into it, you break out of that loop. Notice the usage of break in that loop. Moreover, you did not update the value of count in that else-if condition which causes your loop to run in vain searching for arr2[0] throughout.
Solution:
Remove that break statement.
Add ++count into that else-if condition.
Bonus:
You have written ugly code. You used an extra array which adds to the space complexity of your code and you have too many loops which increases the time complexity as well. You will understand these things later as you progress but for now, I'll give you a better solution:
// Deal with the (0, 0) case outside the loop
// And avoid an extra else-if inside the loop
if (arr[0][0] % 2 == 0)
arr[0][0] = 0;
// There are n diagonal elements in a matrix of order n
// Row and column indexes of a diagonal element are equal
// So you can eliminate the use of j and just rely on i
for (i = 1; i < n; ++i)
// Check if the diagonal element is even and divisible by the sum of the indices
if (arr[i][i] % 2 == 0 && arr[i][i] % (i + i) == 0)
// Replace the element if the condition is satisfied
arr[i][i] = i + i;
As you can see, this approach does not require any extra space and runs in a very good linear time. You may further optimize it by checking if a number is not odd using bitwise AND !(i & 1), and changing i + i into 2 * i which can be done quickly using the bitwise left shift operator (i << 1).
By the way, why do you want arr[0][0] to be replaced? Division by 0 is undefined.
I read the following codes in "The C programming language edition 2"
/* shellsort: sort v[0] ... v[n-1] into increasing order */
void shellsort(int v[], int n) {
int gap, i, j, temp;
for (gap = n/2; gap > 0; gap /= 2)
for (i = gap; i < n; i++)
for (j=i-gap; j>=0 && v[j]>v[j+gap]; j-=gap) {
temp = v[j];
v[j] = v[j+gap];
v[j+gap] = temp;
}
}
What confuse me is that there's no ";" at the end of "for loop line", I assume it should be
for (gap = n/2; gap > 0; gap /= 2) ;
for (i = gap; i < n; i++);
for (j=i-gap; j>=0 && v[j]>v[j+gap]; j-=gap) {
temp = v[j];
v[j] = v[j+gap];
v[j+gap] = temp;
}
How could I wrap it around intuitively?
The statement
for (gap = n/2; gap > 0; gap /= 2) ;
is equal to
for (gap = n/2; gap > 0; gap /= 2)
;
which is equal to
for (gap = n/2; gap > 0; gap /= 2)
{
}
In other words, that's an empty loop that does nothing except the comparison gap > 0 and gap /= 2 (part of the loop) each iteration.
The syntax of the for loop is (simplified for clarity):
for ( ... ) <statement>
statement:
';' // empty statement
<any other statement>
'{' ... '}' // block of statements
So following the for statement comes one statement or a block of statement. And a single ; is a statement, namely the empty (do nothing) statement. So
for (....) ;
for (....) ;
is not a nested for-loop. It is equivalent to:
for (....) ;
for (....) ;
or
for (....) {}
for (....) {}
The for loop runs the next statement in the code the appropriate number of times. Often this statement is a single statement, or a group of statements in curly brackets. If you put a semicolon instead, it's treated as a null statement, and so "nothing" is done the appropriate number of times.
If you explain what you mean when you say "How could I wrap it around intuitively?" that might make it easier to answer your question.
I have my test code (to study the WP loop invariants) which adds two long integers with each digit's representation in an array cell:
int main(int argc, const char * argv[]) {
char a[32], b[32];//size can be very big
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
scanf("%s %s", a, b);
unsigned int size1 = strlen(a);
unsigned int size2 = strlen(b);
//code to reverse a string. currently proved
reverse(a, size1);
reverse(b, size2);
for (unsigned int i = 0; i < size1; i++) a[i]-='0'; //move from chars to integers
for (unsigned int j = 0; j < size2; j++) b[j]-='0';
unsigned int maxsize = size1;
if (size2 > maxsize) maxsize = size2;
int over = 0;
//actual computation code
/*#
loop invariant maxsize == \max(size1, size2);
loop invariant bound: 0 <= k <= maxsize;
loop invariant ov: \forall integer i; 0 < i < k ==> \at(a[i], Here) == (\at(a[i], Pre) + b[i]+ Over((char *)a, (char *)b, i)) % 10;
loop assigns k, a[0..maxsize-1],over;
loop variant maxsize - k;
*/
for (unsigned int k = 0; k < maxsize; k++)
{
char sum=a[k] + b[k] + over;
//over=overflow is for 9+9 = 18, result=8, over=1
a[k] = sum % 10;
over = sum / 10;
}
if (over != 0) a[maxsize++] = over;
//...
return 0;
}
I want to specify only the last loop invariant. I have already tried some pieces of ACSL code with \at(a[i], LoopCurrent). I received Unknown status or Timeout. Finally, I finished with an axiomatic recursive solution without any success.
I have no ideas now what else should I try to verify this. Help?
UPDATE:
Created a function for actual calculations. Improved axioms. Still got Timeout status. Ran with Frama-C latest release from opam with default settings (timeout=10, prover Alt-Ergo).
/*#
#predicate
Unchanged{K,L}(char* a, integer first, integer last) = \forall integer i; first <= i < last ==> \at(a[i],K) == \at(a[i],L);
axiomatic ReminderAxiomatic
{
logic integer Reminder {l} (integer x, integer y);
axiom ReminderEmpty: \forall integer x, integer y; x < y ==> Reminder(x, y) == x;
axiom ReminderNext: \forall integer x, integer y; x>=y ==> Reminder(x, y) == Reminder(x-y, y)+0;
}
axiomatic DivAxiomatic
{
logic integer Div {l} (integer x, integer y);
axiom DivEmpty: \forall integer x, integer y; x < y ==> Div(x, y) == 0 ;
axiom DivNext: \forall integer x, integer y; x >= y ==> Div(x, y) == Div(x - y, y) + 1 ;
}
axiomatic OverAxiomatic
{
logic integer Over {L}(char *a, char * b, integer step) reads a[0..step-1], b[0..step-1];
axiom OverEmpty: \forall char *a, char * b, integer step; step <= 0 ==> Over(a, b, step) == 0;
axiom OverNext: \forall char *a, char * b, integer step; step > 0 && a[step-1]<10 && a[step-1]>=0 && b[step-1]<10 && b[step-1]>=0
==> Over(a, b, step) == Div((int) a[step-1]+(int)b[step-1]+(int)Over(a,b,step-1), 10);
}
*/
/*#
requires 0 <= maxsize < 10;
requires \valid (a+(0..maxsize-1));
requires \valid (b+(0..maxsize-1));
requires \valid (res+(0..maxsize));
requires \forall integer i; 0 <= i < maxsize ==> 0 <= (int)a[i] < 10;
requires \forall integer i; 0 <= i < maxsize ==> 0 <= (int)b[i] < 10;
*/
void summ(char *a, char *b, char *res, unsigned int maxsize) {
char over = 0;
/*#
loop invariant bound: 0 <= k <=maxsize;
loop invariant step: \forall integer i; 0 <= i < k ==> res[i] == (char) Reminder((int)a[i]+ (int)b[i]+ (int)Over((char *)a, (char *)b, i) , 10);
loop invariant unch: Unchanged{Here,LoopEntry}((char *)res, k, maxsize);
loop assigns k, over, res[0..maxsize-1];
loop variant maxsize-k;
*/
for (unsigned int k = 0; k < maxsize; k++)
{
char sum = a[k] + b[k] + over;
res[k] = sum % 10;
over = sum / 10;
}
//
if (over != 0) res[maxsize++] = over;
}
First of all, it would be much better if your question contained a MCVE, which in the present case include the C function you're currently working on (instead of only its body), and the ACSL annotations you've written, at their exact place in the code. The command line used to launch Frama-C wouldn't hurt either, as well as the list of annotations for which you have trouble.
Apart from that, here are a few things that might be related to your problem (again, without an exact description, it's difficult to tell for sure).
the loop assigns is wrong: you're assigning over in the loop, but it is not mentioned there.
I'm unsure whether \max is well supported by WP.
modulo and integer division are two operations automated provers tend to struggle with. You might need a few additional assertions and/or axioms to help them.
your loop invariant does not say anything about the values of a[i] for k <= i< maxsize. Since loop assigns indicates that all cells of a might have been modified, you have to add an invariant telling that the ones with higher indices have not been touched so far.
I'm not completely sure about your usage of \at(a[i],Pre): Pre indicates the beginning of the current function. Thus, if scanf and reverse are in the same function as the loop (again, a MCVE would have clarified this), this is not true. You might want to speak about \at(a[i],Loop_entry) to refer to the value of the cell in the state in which the loop is entered for the first time.
UPDATE
I'm afraid WP will not be able to completely prove your annotations, but I managed to obtain a version in which only a single lemma, that is basically an expanded version of the reads clause for the Over function is left unproved (and I believe that there is no way to prove it under WP's actual representation of C memory). Note that it implies playing with the TIP feature of WP. Code and scripts are provided below, but I'll start by commenting on your original version:
there is no need for Div and Reminder. If anything, they will confuse the prover. You can stick with xxx/10 and xxx%10. In fact, my remark on division and modulo was a bit too cautious. In the present case, everything seems to be fine at this level.
Similarly, Unchanged could be inlined, but it shouldn't hurt to keep it that way.
I have used unsigned char instead of char, as it avoids some spurious conversions due to integer promotions, and removed any cast in the logic. You normally don't have to introduce such casts in ACSL annotations, except perhaps to indicate that some computation stays within an appropriate range (as in \let x = y + z; x == (int) x; ). Such casts are translated into function calls in the proof obligation, and again it can confuse the provers.
an invariant was missing to indicate that over does indeed contain the potential carry from the previous step (again, a good hint that you're missing an invariant is that a location mentioned in loop assigns does not appear in any loop invariant).
Finally, there is a small subtlety: if you don't indicate somehow that over can only be 0 or 1, there's nothing that prevent the addition to overflow the unsigned char (making it impossible to prove that a C computation with unsigned char and its ACSL counterpart with unbounded integers give the same result). Due to the recursive nature of the Over function, this can be established by a so-called lemma function in which the mathematical induction is carried out by a simple for loop with appropriate invariants
In addition, I've added explicitely as invariant that a and b are left untouched. This is normally implied by the loop assigns, but having these explicit hypotheses makes it easier during the scripts.
To sum up, here is the final code:
/*#
axiomatic Carry {
logic integer Over {L}(unsigned char* a, unsigned char* b, integer step)
reads a[0 .. step - 1], b[0 .. step - 1];
axiom null_step: \forall unsigned char* a, *b, integer step;
step <= 0 ==> Over(a,b,step) == 0;
axiom prev_step: \forall unsigned char* a, *b, integer step;
step > 0 ==>
Over(a,b,step) ==
(a[step-1] + b[step - 1] + Over(a,b,step-1)) / 10;
lemma OverFootPrint{L1,L2}:
\forall unsigned char* a, unsigned char*b, integer step;
(\forall integer i; 0<=i<step ==> \at(a[i],L1) == \at(a[i],L2)) &&
(\forall integer i; 0<=i<step ==> \at(b[i],L1) == \at(b[i],L2)) ==>
Over{L1}(a,b,step) == Over{L2}(a,b,step);
}
*/
/*#
requires \valid(a+(0 .. step-1));
requires \valid(b+(0 .. step - 1));
requires \forall integer i; 0<=i<step ==> 0<=a[i]<10 && 0<=b[i]<10;
assigns \nothing;
ensures 0<= Over(a,b,step) <= 1;
*/
void lemma_function(unsigned char* a, unsigned char* b, unsigned int step) {
/*#
loop invariant 0<=i<=step;
loop invariant \forall integer k; 0<=k<=i ==> 0 <= Over(a, b, k) <= 1;
loop assigns i;
*/
for (int i = 0; i < step; i++);
}
/*#
requires 0 <= maxsize < 10;
requires \valid (a+(0..maxsize-1));
requires \valid (b+(0..maxsize-1));
requires \valid (res+(0..maxsize));
requires \separated (a+(0..maxsize-1),res+(0..maxsize));
requires \separated (b+(0..maxsize-1),res+(0..maxsize));
requires \forall integer i; 0 <= i < maxsize ==> 0 <= a[i] < 10;
requires \forall integer i; 0 <= i < maxsize ==> 0 <= b[i] < 10;
*/
void summ(unsigned char* a, unsigned char*b, unsigned char* res,
unsigned int maxsize) {
unsigned char over = 0;
/*#
loop invariant bound: 0 <= k <=maxsize;
loop invariant step: \forall integer i; 0 <= i < k ==> res[i] == (a[i]+ b[i]+ Over(a,b,i)) % 10;
loop invariant over: over == Over(a,b,k);
loop invariant a_unchanged: \forall integer i; 0 <= i < maxsize ==>
\at(a[i],LoopEntry) == a[i];
loop invariant b_unchanged: \forall integer i; 0 <= i < maxsize ==>
\at(b[i],LoopEntry) == b[i];
loop invariant unch: \forall integer i; k<=i<=maxsize ==> \at(res[i],LoopEntry) == res[i];
loop assigns k, over, res[0..maxsize-1];
loop variant maxsize-k;
*/
for (unsigned int k = 0; k < maxsize; k++)
{
unsigned char sum = a[k] + b[k] + over;
res[k] = sum % 10;
over = sum / 10;
lemma_function(a,b,k);
}
//
if (over != 0) res[maxsize++] = over;
}
The two TIP scripts are available here. To use them, put them in a directory scripts/typed next to the code (say file.c) and use this command line:
frama-c[-gui] -wp -wp-prover alt-ergo,script -wp-session scripts file.c
You can change the name of the scripts directory if you wish (it must match the argument of -wp-session), but typed and the filenames of the scripts must be as given since WP will use them to detect which proof obligation they are supposed to prove. In GUI mode, you can have a look at the script, but it is probably difficult to understand and explaining each step will not fit in a SO's answer.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I'm trying to prove this function, but in vain. I'm also using another function, but I proved it.
Could anyone help me?
I'm using Frama-C Sodium version with Alt-ergo 3 as prover.
Given a not-empty string x. An integer number p such that
0 < p ≤|x| is meant to be "a period of x" if
x[i] = x[i + p]
for i = 0, 1, ... , |x| − p − 1.
Note that, for each not-empty string, the length of the string
is a period of itself. In this way, every not-empty string
has got at least one period. So is well formed the concept of minimum
period of string x, denoted by per(x):
per(x) = min { p | p is period of x }.
Write a C function
unsigned per(const char x[], unsigned l)
that, given a string x of length l, returns per(x).
Here is the code and the specifications I have written so far:
/*#
requires l > 0;
requires p >= 0;
behavior zero:
assumes p == l;
ensures \result == 1;
behavior one:
assumes l != p && (l%p) == 0;
assumes \forall int i; 0 <= i < l-p-1 ==> x[i] == x[i+p];
ensures \result == 1;
behavior two:
assumes l != p && (l%p) == 0;
assumes !(\forall int i; 0 <= i < l-p-1 ==> x[i] == x[i+p]);
ensures \result == 0;
behavior three:
assumes p != l && l%p != 0;
ensures \result == 0;
complete behaviors;
disjoint behaviors;
*/
unsigned has_period(const char x[], unsigned int p, unsigned l) {
if (p == l) return 1;
if ((l % p) != 0) return 0;
/*#
loop assigns i;
loop invariant \forall int j; 0 <= j < i ==> (x[j] == x[j+p]);
loop invariant i <= l-p-1;
loop invariant i >= 0;
*/
for (int i = 0 ; i < l-p-1 ; ++i) {
if (x[i] != x[i + p])
return 0;
}
return 1;
}
/*
predicate has_period(char* x, unsigned int p, unsigned l) =
\forall int i; i < (l-p-1) ==> x[i] == x[i+p];
*/
/*#
requires l > 0;
requires \valid(x+(0..l-1));
ensures 1 <= \result <= l;
ensures \forall unsigned int i; i < (l-\result-1) ==> x[i] == x[i+\result];
ensures \forall unsigned int p; 1 <= p < \result ==> !(\forall int i; i < (l-p-1) ==> x[i] == x[i+p]);
*/
unsigned per(const char x[], unsigned l) {
int p = 1;
/*#
loop assigns p;
loop invariant 1 <= p <= l;
loop invariant \forall unsigned j; 1 <= j < p ==> !(\forall int i; i < (l-j-1) ==> x[i] == x[i+j] || (l%p) == 0);
loop invariant p >= 0;
*/
while(p < l && !has_period(x,p,l))
++p;
return p;
}
It would have helped if you had told us what your specific issue was, instead of a generic "it doesn't work", but here are some points:
Your contracts are lacking assigns clause. These are not optional when using WP, especially for functions like has_period that are called within your development. WP needs those clauses to know which locations might have changed during the call, and by taking the complement, which locations have stayed the same.
You have given a nice semi-formal definition of what a periodic string is. You should use that to define an ACSL predicate periodic (taking the same arguments as your C function has_period), and write your specifications according to this predicate. This will simplify your annotations a lot. In particular has_period does not need 4 behaviors: if periodic holds it must return 1, if periodic does not hold, it must return 0.
Using -wp-rte leads to a bunch of unproved obligations. Depending on your assignment, you might want to strengthen your specifications, especially regarding the validity of the location pointed to by x.