Hint on FStar proof dead end - fstar

Can I get a brief explanation why this proof effort fails?
In my studies I'm trying to recognize simple patterns in generated lists of integers.
The generator below produces a list of alternating 0s and 1s. I'd like to prove that items at even indexes are 0.
val evenb : nat -> bool
let rec evenb n =
match n with
| 0 -> true
| 1 -> false
| n -> evenb (n - 2)
val nth_item : ls: list nat {length ls > 0} -> n: nat {n < length ls} -> nat
let rec nth_item ls n =
match ls with
| [h] -> h
| h :: t -> if n = 0 then h else nth_item t (n - 1)
val gen_01 : lng: nat {lng >= 2 && evenb lng} -> ls: list nat {length ls = lng}
let rec gen_01 lng =
match lng with
| 2 -> [0; 1]
| _ -> [0; 1] # gen_01 (lng - 2)
let rec lemma_01 (lng: nat {lng >= 2 && evenb lng}) :
Lemma (forall (n: nat {n <= lng - 2 && evenb n}) . (nth_item (gen_01 lng) n) = 0) =
match lng with
| 2 -> ()
| _ -> lemma_01 (lng - 2)
FStar returns 'could not prove post-condition'.
I'd appreciate any help regarding the approach.

F* should also report a secondary error location pointing to the conjunct in the postcondition that was not provable---in this case, it's just the nth_item (gen_01 lng) n = 0 goal.
One way to diagnose this is to consider one branch of the proof at a time. E.g. if you add an admit(); in the second branch, then you'll see that the first branch is easily provable. So, what's going wrong is the inductive case. You don't have a strong enough induction hypothesis to prove the property you want.
Here's one proof of it ... there are probably many others.
First, I proved this:
let rec access_2n (l:nat{l >= 2 && evenb l}) (n:nat{2 * n < l})
: Lemma (ensures nth_item (gen_01 l) (2 * n) = 0)
= match n with
| 0 -> ()
| _ -> access_2n (l - 2) (n - 1)
Notice the induction on the pair l, n so that the length and the access index decrease together.
This is pretty much the property you wanted to prove, stated slightly differently. To massage it into the form you want, I did this:
First, a lemma to interpret evenb arithmetically:
[Edit: I added an open FStar.Mul to bring the * symbol into scope for multiplication]
open FStar.Mul
let rec evenb_is_even (n:nat{evenb n})
: Lemma (2 * (n / 2) = n)
= match n with
| 0 -> ()
| _ -> evenb_is_even (n - 2)
Then to prove something very like your lemma, but for an explicit n.
let lemma_01_aux (lng: nat {lng >= 2 && evenb lng}) (n:nat{n <= lng - 2 && evenb n})
: Lemma (nth_item (gen_01 lng) n = 0)
= access_2n lng (n / 2); evenb_is_even n
And finally to universally quantify over n using a library that turns lemmas into quantified postconditions.
let lemma_01 (lng: nat {lng >= 2 && evenb lng})
: Lemma (forall (n: nat {n <= lng - 2 && evenb n}) . (nth_item (gen_01 lng) n) = 0)
= FStar.Classical.forall_intro_2 lemma_01_aux

Related

Why is this OCaml code resulting in a runtime error?

I am trying to run the following code on a coding question website and it says there is a runtime error, but running it on the top-level ocaml seems to work fine. Could there be any source of error in the code? Thanks in advance
The question is to find the number of 'good segments' within the given list and a specific number. A good segment is defined as follows:
A and B are positive integers such that A < B.
x that satisfies A <= x <= B is not an element of the given list.
The following are the inputs.
n, which is the number of elements in the list that will be given.
a, b, c, ... which are the elements of the list.
t, which is the number that must be included in the segment.
The output should be a single number printed out.
Edited Code:
let rec drop_value l to_drop =
match l with
| [] -> []
| hd :: tl ->
let new_tl = drop_value tl to_drop in
if hd = to_drop then new_tl else hd :: new_tl
;;
let rec find_start li t cur_min =
match li with
| [] -> cur_min
| hd :: tl -> let new_min = abs (t - hd) in
if new_min = 0 then find_start tl t new_min
else if new_min < cur_min && t > hd then find_start tl t new_min
else find_start tl t cur_min
;;
let rec find_end li t cur_min =
match li with
| [] -> cur_min
| hd :: tl -> let new_min = abs (t - hd) in
if new_min = 0 then find_end tl t new_min
else if new_min < cur_min && t < hd then find_end tl t new_min
else find_end tl t cur_min
;;
let rec contains_value l value =
match l with
| [] -> false
| hd :: tl -> if hd = value then true else contains_value tl value
;;
let nums = ref [];;
let n = read_int () in
for i = 1 to n do
Scanf.scanf " %d" (fun a ->
nums := a :: !nums)
done;
Scanf.scanf " %d" (fun t ->
if contains_value !nums t then print_int 0
else let start = if List.length !nums = 1 then 1 else abs (find_start !nums t 1001 - t) in
let finish = find_end (drop_value !nums start) t 1001 + t in
if t > start && t < finish then (if start = 1 && List.length ! nums = 1 then print_int ((t - start + 1) * (finish - t) - 1) else print_int ((t - start) * (finish - t) - 1))
else let start = 1 in print_int ((t - start + 1) * (finish - t) - 1))
;;
eg.
5
4 8 13 24 30
10
should give
5
=> [9, 10], [9, 11], [9, 12], [10, 11], [10, 12]
You don't describe the exact input format that your code is going to get. This makes it pretty much impossible to debug your code.
When I compile and run your code (as m.ml) using the input you describe I see this:
$ ./m
5 4 8 13 24 30 10
Fatal error: exception Failure("int_of_string")
In fact no matter what format I try for the input I get the same result.
So that is probably what is happening at the website.
In my experience it always causes more harm than good to use scanf. Combining it with other input functions is probably going to make things worse.
If you describe the expected format of the input carefully, somebody on StackOverflow can recommend a way to get your numbers.
In the meantime here's a way to read all the numbers on one line:
let rec split_at list n =
if n = 0 then
([], list)
else
match list with
| [] -> ([], [])
| h :: t ->
let (a, b) = split_at t (n - 1) in (h :: a, b)
in
let (nums, t) =
let line = read_line () in
let nstrs = Str.split (Str.regexp "[ \t][ \t]*") line in
match List.map int_of_string nstrs with
| [] -> failwith "no numbers"
| n :: rest ->
if List.length rest <> n + 1 then
failwith "bad count"
else
let (nums, tlist) = split_at rest n in
(nums, List.hd tlist)
in
. . .

Adding 0-s to a list of until it's length is 8 in Haskell

So I have to make a decimal number into binary list like so: intToBitString 4 = [1,0,0].
Which i have done like so:
intToBitString n = reverse (helper n)
helper 0 = []
helper n
| n `mod` 2 == 1 = 1 : helper (n `div` 2)
| n `mod` 2 == 0 = 0 : helper(n `div` 2)
But then I also have to make a function called intToByte, which pads out the list with 0-s until it's length is 8 elements long. (so making it a bytestring) Like this:
intToByte 7 = [0, 0, 0, 0, 0, 1, 1, 1]
I have tried so many things, but they never work. I am a beginner, so I only know the "if" loop the way I showed above, and recursion, but I dont know anything fancy. One of my tries:
intToByte 0 = [0]
intToByte n
| eight n == helper2 n = reverse (helper2 n)
| otherwise = eight n
helper2 0 = []
helper2 n
| n `mod` 2 == 1 = 1 : helper2 (n `div` 2)
| n `mod` 2 == 0 = 0 : helper2 (n `div` 2)
eight n
| length (helper2 n) < 8 = 0 : eight n
| otherwise = helper2 n
I have been working on this for so many hours that i'm getting confused by it. But this is part of an important assignment, so help would be very appreciated!
First of all, you can simplify your code with:
helper2 :: Integral i => i -> [i]
helper2 0 = []
helper2 n = r : helper2 q
where (q,r) = quotRem n 2
Secondly, the above is a big endian representation [wiki]. Indeed, 7 is represented as [1,1,1], whereas 14 is for example represented as [0,1,1,1]. If we want to revers this, we can work with an accumulator:
helper2 :: Integral i => i -> [i]
helper2 = go []
where go rs 0 = rs
go rs n = go (r:rs) q
where (q,r) = quotRem n 2
This thus maps 7 to [1,1,1] and 14 to [1,1,1,0]. But now we still need to add leading zeros. We can do that for example by maintaing the number of elements already added to the list:
eight :: Integral i => i -> [i]
eight = go [] 0
where go rs l 0 = replicate (8-l) 0 ++ rs
go rs l n = go (r:rs) (l+1) q
where (q,r) = quotRem n 2
Padding can be as simple as computing how many additional elements to push to the list and then have those elements produced using the function replicate from the Prelude:
padLeft :: Int -> a -> [a] -> [a]
padLeft n x xs = replicate (n - length xs) x ++ xs
For instance:
> padLeft 8 0 [1, 1, 0]
[0,0,0,0,0,1,1,0]
One approach would be to define a function bits such that bits k converts its argument to a bit string of length k:
bits :: Int -> Int -> [Int]
bits 0 _n = []
bits k n | n < 0 = error "bits: negative"
| n > 2 * m - 1 = error "bits: overflow"
| otherwise = let (i, j) = n `divMod` m in i : bits (k - 1) j
where m = 2 ^ (k - 1)
Your function eight is then easily written as
eight :: Int -> [Int]
eight = bits 8
This gives:
> eight 4
[0,0,0,0,0,1,0,0]
> eight 7
[0,0,0,0,0,1,1,1]

F# Performance: What is making this code so slow?

This F# code is an attempt to solve Project Euler problem #58:
let inc = function
| n -> n + 1
let is_prime = function
| 2 -> true
| n when n < 2 || n%2=0-> false
| n ->
[3..2..(int (sqrt (float n)))]
|> List.tryFind (fun i -> n%i=0)
|> Option.isNone
let spir = Seq.initInfinite (fun i ->
let n = i%4
let a = 2 * (i/4 + 1)
(a*n) + a + (a-1)*(a-1))
let rec accum se p n =
match se with
| x when p*10 < n && p <> 0 -> 2*(n/4) + 1
| x when is_prime (Seq.head x) -> accum (Seq.tail x) (inc p) (inc n)
| x -> accum (Seq.tail x) p (inc n)
| _ -> 0
printfn "%d" (accum spir 0 1)
I do not know the running time of this program because I refused to wait for it to finish. Instead, I wrote this code imperatively in C++:
#include "stdafx.h"
#include "math.h"
#include <iostream>
using namespace std;
int is_prime(int n)
{
if (n % 2 == 0) return 0;
for (int i = 3; i <= sqrt(n); i+=2)
{
if (n%i == 0)
{
return 0;
}
}
return 1;
}
int spir(int i)
{
int n = i % 4;
int a = 2 * (i / 4 + 1);
return (a*n) + a + ((a - 1)*(a - 1));
}
int main()
{
int n = 1, p = 0, i = 0;
cout << "start" << endl;
while (p*10 >= n || p == 0)
{
p += is_prime(spir(i));
n++; i++;
}
cout << 2*(i/4) + 1;
return 0;
}
The above code runs in less than 2 seconds and gets the correct answer.
What is making the F# code run so slowly? Even after using some of the profiling tools mentioned in an old Stackoverflow post, I still cannot figure out what expensive operations are happening.
Edit #1
With rmunn's post, I was able to come up with a different implementation that gets the answer in a little under 30 seconds:
let inc = function
| n -> n + 1
let is_prime = function
| 2 -> true
| n when n < 2 || n%2=0-> false
| n ->
[3..2..(int (sqrt (float n)))]
|> List.tryFind (fun i -> n%i=0)
|> Option.isNone
let spir2 =
List.unfold (fun state ->
let p = fst state
let i = snd state
let n = i%4
let a = 2 * (i/4 + 1)
let diag = (a*n) + a + (a-1)*(a-1)
if p*10 < (i+1) && p <> 0 then
printfn "%d" (2*((i+1)/4) + 1)
None
elif is_prime diag then
Some(diag, (inc p, inc i))
else Some(diag, (p, inc i))) (0, 0)
Edit #2
With FuleSnabel's informative post, his is_prime function makes the above code run in under a tenth of a second, making it faster than the C++ code:
let inc = function
| n -> n + 1
let is_prime = function
| 1 -> false
| 2 -> true
| v when v % 2 = 0 -> false
| v ->
let stop = v |> float |> sqrt |> int
let rec loop vv =
if vv <= stop then
if (v % vv) <> 0 then
loop (vv + 2)
else
false
else
true
loop 3
let spir2 =
List.unfold (fun state ->
let p = fst state
let i = snd state
let n = i%4
let a = 2 * (i/4 + 1)
let diag = (a*n) + a + (a-1)*(a-1)
if p*10 < (i+1) && p <> 0 then
printfn "%d" (2*((i+1)/4) + 1)
None
elif i <> 3 && is_prime diag then
Some(diag, (inc p, inc i))
else Some(diag, (p, inc i))) (0, 0)
There is no Seq.tail function in the core F# library (UPDATE: Yes there is, see comments), so I assume you're using the Seq.tail function from FSharpx.Collections. If you're using a different implementation of Seq.tail, it's probably similar -- and it's almost certainly the cause of your problems, because it's not O(1) like you think it is. Getting the tail of a List is O(1) because of how List is implemented (as a series of cons cells). But getting the tail of a Seq ends up creating a brand new Seq from the original enumerable, discarding one item from it, and returning the rest of its items. When you go through your accum loop a second time, you call Seq.tail on that "skip 1 then return" seq. So now you have a Seq which I'll call S2, which asks S1 for an IEnumerable, skips the first item of S1, and returns the rest of it. S1, when asked for its first item, asks S0 (the original Seq) for an enumerable, skips its first item, then returns the rest of it. So for S2 to skip two items, it had to create two seqs. Now on your next run through when you ask for the Seq.tail of S2, you create S3 that asks S2 for an IEnumerable, which asks S1 for an IEnumerable, which asks S0 for an IEnumerable... and so on. This is effectively O(N^2), when you thought you were writing an O(N) operation.
I'm afraid I don't have time right now to figure out a solution for you; using List.tail won't help since you need an infinite sequence. But perhaps just knowing about the Seq.tail gotcha is enough to get you started, so I'll post this answer now even though it's not complete.
If you need more help, comment on this answer and I'll come back to it when I have time -- but that might not be for several days, so hopefully others will also answer your question.
Writing performant F# is very possible but requires some knowledge of patterns that have high relative CPU cost in a tight loop. I recommend using tools like ILSpy to find hidden overhead.
For instance one could imagine F# exands this expression into an effective for loop:
[3..2..(int (sqrt (float n)))]
|> List.tryFind (fun i -> n%i=0)
|> Option.isNone
However it currently doesn't. Instead it creates a List that spans the range using intrinsic operators and passes that to List.tryFind. This is expensive when compared to the actual work we like to do (the modulus operation). ILSpy decompiles the code above into something like this:
public static bool is_prime(int _arg1)
{
switch (_arg1)
{
case 2:
return true;
default:
return _arg1 >= 2 && _arg1 % 2 != 0 && ListModule.TryFind<int>(new Program.Original.is_prime#10(_arg1), SeqModule.ToList<int>(Operators.CreateSequence<int>(Operators.OperatorIntrinsics.RangeInt32(3, 2, (int)Math.Sqrt((double)_arg1))))) == null;
}
}
These operators aren't as performant as they could be (AFAIK this is currently being improved) but no matter how effecient allocating a List and then search it won't beat a for loop.
This means the is_prime is not as effective as it could be. Instead one could do something like this:
let is_prime = function
| 1 -> false
| 2 -> true
| v when v % 2 = 0 -> false
| v ->
let stop = v |> float |> sqrt |> int
let rec loop vv =
if vv <= stop then
(v % vv) <> 0 && loop (vv + 2)
else
true
loop 3
This version of is_prime relies on tail call optimization in F# to expand the loop into an efficient for loop (you can see this using ILSpy). ILSpy decompile the loop into something like this:
while (vv <= stop)
{
if (_arg1 % vv == 0)
{
return false;
}
int arg_13_0 = _arg1;
int arg_11_0 = stop;
vv += 2;
stop = arg_11_0;
_arg1 = arg_13_0;
}
This loop doesn't allocate memory and is just a rather efficient loop. One see some non-sensical assignments but hopefully the JIT:er eliminate those. I am sure is_prime can be improved even further.
When using Seq in performant code one have to keep in mind it's lazy and it doesn't use memoization by default (see Seq.cache). Therefore one might easily end up doing the same work over and over again (see #rmunn answer).
In addition Seq isn't especially effective because of how IEnumerable/IEnumerator are designed. Better options are for instance Nessos Streams (available on nuget).
In case you are interested I did a quick implementation that relies on a simple Push Stream which seems decently performant:
// Receiver<'T> is a callback that receives a value.
// Returns true if it wants more values, false otherwise.
type Receiver<'T> = 'T -> bool
// Stream<'T> is function that accepts a Receiver<'T>
// This means Stream<'T> is a push stream (as opposed to Seq that uses pull)
type Stream<'T> = Receiver<'T> -> unit
// is_prime returns true if the input is prime, false otherwise
let is_prime = function
| 1 -> false
| 2 -> true
| v when v % 2 = 0 -> false
| v ->
let stop = v |> float |> sqrt |> int
let rec loop vv =
if vv <= stop then
(v % vv) <> 0 && loop (vv + 2)
else
true
loop 3
// tryFind looks for the first value in the input stream for f v = true.
// If found tryFind returns Some v, None otherwise
let tryFind f (s : Stream<'T>) : 'T option =
let res = ref None
s (fun v -> if f v then res := Some v; false else true)
!res
// diagonals generates a tuple stream of all diagonal values
// The first value is the side length, the second value is the diagonal value
let diagonals : Stream<int*int> =
fun r ->
let rec loop side v =
let step = side - 1
if r (side, v + 1*step) && r (side, v + 2*step) && r (side, v + 3*step) && r (side, v + 4*step) then
loop (side + 2) (v + 4*step)
if r (1, 1) then loop 3 1
// ratio computes the streaming ratio for f v = true
let ratio f (s : Stream<'T>) : Stream<float*'T> =
fun r ->
let inc r = r := !r + 1.
let acc = ref 0.
let count = ref 0.
s (fun v -> (inc count; if f v then inc acc); r (!acc/(!count), v))
let result =
diagonals
|> ratio (snd >> is_prime)
|> tryFind (fun (r, (_, v)) -> v > 1 && r < 0.1)

Check list for consecutive values within range (F#)

In a sorted list of 10 numbers, I want to find out whether any 5 consecutive numbers are within a certain range. For reference: This is called finding a "stellium" (astronomical term, regarding positions of planets).
If the list is:
let iList = [15; 70; 72; 75; 80; 81; 120; 225; 250; 260]
I want a function
let hasStellium iStellSize iStellRange iList
that will return
hasStellium 5 20 iList = true
The list is already sorted, so I could just proceed with clunky if-then statements (like "Check whether element 1 and 5 are less than 20 units apart, check whether element 2 and 6 satisfy the condition" etc.
let hasStellium iStellSize iStellRange iList=
if
iList.[iStellSize-1] - iList.[0] < iStellRange ||
iList.[iStellSize] - iList.[1] < iStellRange
then true
else false
But there must be a more elegant way, that also allows for other stellium sizes without having to manually add if-then lines.
Thank you very much for your help!
(If the function could return the index number where the stellium starts, even better)
Just combining two standard library functions:
let hasStellium iStellSize iStellRange iList =
iList |> Seq.windowed iStellSize
|> Seq.tryFindIndex (fun s -> (s.[iStellSize - 1] - s.[0] < iStellRange))
returns either None if no such range can be found, otherwise Some x where x - range beginning index.
Here you go. It returns an int option which is the start index of the range, or None if not found.
let tryFindStelliumIndex iStellSize iStellRange iList =
let rec findRange i n = function
| _ when (n + 1) = iStellSize -> Some (i - n)
| prev::cur::tail when (cur - prev) < iStellRange -> findRange (i + 1) (n + 1) (cur::tail)
| _::tail -> findRange (i + 1) 0 tail
| _ -> None
findRange 0 0 iList
Another variant using Seq functions:
let hasStellium size range l =
Seq.zip l (l |> Seq.skip (size - 1))
|> Seq.tryFindIndex (fun p -> snd p - fst p < range)
Had to hack in an "early return" with a mutable variable, but here is a rough version
let mutable found = false
for i = 0 to (iList |> List.length - iStellSize) do
if iList.[i + iStellSize] - iList.[i] <= iStellRange then //Did you mean < or <=?
found <- true
found

Why does pattern with variable not match?

I'm writing a code that can find the median of a list, and I cannot use rec and should use List.fold_left/right. I wrote the following code, which should work.
It finds the length of the list, if it's an odd number like 5, then it sets len1, len2 to 2, 3, if it's an even number like 6, then it sets len1, len2 to 2, 3.
Then for each member in the list I match the number of those elements that are less than it.
However, the following pattern matching always math lessNum elmt to len1 - can someone tell me why it is so?
let median (lst : int list) : float option =
let len = List.length lst in
if lst = [] then None
else
let len1, len2 = (len - 1) / 2, (len + 1) / 2 in
let lessNum a =
List.length (List.find_all (fun n -> n < a) lst) in
let answer = List.fold_left (fun accm elmt ->
match (lessNum elmt) with
| len1 -> accm + elmt
| len2 -> failwith "len2"
| _ -> failwith "other"
) 0 lst in
if len mod 2 = 0
then Some ((float_of_int answer) /. 2.0)
else Some (float_of_int answer)
An identifier appearing in a pattern always matches, and binds the corresponding value to the identifier. Any current value of the identifier doesn't matter at all: the pattern causes a new binding, i.e., it gives a new value to the identifier (just inside the match).
# let a = 3;;
val a : int = 3
# match 5 with a -> a;;
- : int = 5
# a;;
- : int = 3
#
So, your match statement isn't doing what you think it is. You'll probably have to use an if for that part of your code.
Update
Here's how to use an association list to approximate the function f in your followup question:
let f x = List.assoc x [(pat1, ans1); (pat2, ans2)]
This will raise a Not_found exception if x is not equal to pat1 or pat2.
(I think your Python code is missing return.)