I try to prove the following lemma. It seems really trivial, but I can't manage to prove it. Thank you in advance!
lemma test(x : seq<int>)
// if the values from x are margined by an interval
// the values are different
// and the number of values equals the size of the interval
// then all values from the interval appear in x
requires forall i :: 0 <= i < |x| ==>
0 <= x[i] < |x|;
requires forall i :: 0 <= i < |x| ==>
forall i' :: 0 <= i' < |x| && i != i' ==>
x[i] != x[i'];
ensures forall v :: 0 <= v < |x| ==>
exists i :: 0 <= i < |x| && x[i] == v;
{
}
https://rise4fun.com/Dafny/d8VK
Here's one way to do it, using some facts about set cardinalities.
lemma test(x : seq<int>)
// if the values from x are margined by an interval
// the values are different
// and the number of values equals the size of the interval
// then all values from the interval appear in x
requires forall i :: 0 <= i < |x| ==>
0 <= x[i] < |x|;
requires forall i :: 0 <= i < |x| ==>
forall i' :: 0 <= i' < |x| && i != i' ==>
x[i] != x[i'];
ensures forall v :: 0 <= v < |x| ==> v in x
{
var L: set<int>, R: set<int> := {}, RangeSet(0, |x|);
var i := 0;
CardinalityRangeSet(0, |x|);
while i < |x|
invariant 0 <= i <= |x|
invariant L == set j | 0 <= j < i :: x[j]
invariant forall v | v in L :: v in x
invariant forall v | 0 <= v < |x| :: v in L || v in R
invariant |R| == |x| - i
{
L, R := L + {x[i]}, R - {x[i]};
i := i + 1;
}
}
predicate InRange(lo: int, hi: int, i: int)
{
lo <= i < hi
}
function RangeSet(lo: int, hi: int): set<int>
{
set i | lo <= i < hi && InRange(lo, hi, i)
}
lemma CardinalityRangeSet(lo: int, hi: int)
decreases hi - lo
ensures |RangeSet(lo, hi)| == if lo >= hi then 0 else hi - lo
{
if lo < hi {
assert RangeSet(lo, hi) == {lo} + RangeSet(lo + 1, hi);
CardinalityRangeSet(lo + 1, hi);
}
}
I changed your specification slightly to use the Dafny syntax v in x, which is equivalent to what you wrote, and a little easier for Dafny to reason about.
The basic idea of the proof is to start with the range R of elements 0..|x|, and then iteratively remove elements x[i] from R and add them to L. This maintains the invariant that every number in the range 0..|x| is either in L or R, while the cardinality of R decreases on every iteration. Thus, at the end of the loop R is empty, so every number in the range must be in L, and therefore in x.
I also used one helper lemma proved by induction to show that RangeSet has the expected size.
(Edited to get rid of "No terms found to trigger on" warning in RangeSet. Introducing the predicate InRange gives it something to trigger on, but you still need to include the explicit range in RangeSet because otherwise it can't figure that the set is finite.)
Related
I want to create a function as mentioned in the title. The specific is that it adds the digits in reversed order, you can see that in the test cases: 12 -> 1; 852369 -> 628; 1714 -> 11; 12345 -> 42; 891 -> 9; 448575 -> 784; 4214 -> 14
The main idea is that when the number is bigger than 99 it enters the helper function which has i - indicator if the the digit is on an even position, and res which stores the result. Helper begins to cycle n as it checks whether or not the current digit is on even position and adds it to the result.
So far I've tried the following code:
everyOther :: Int -> Int
everyOther n
| n < 10 = error "n must be bigger than 10 or equal"
| n < 100 = div n 10
| otherwise = helper n 0 0
where
helper :: Int -> Int -> Int -> Int
helper n i res
| n < 100 = res
| i == 1 = helper (div n 10) (i - 1) (res + (mod n 10)*10)
| otherwise = helper (div n 10) i res
Any help would be appreciated!
You can obtain the one but last digit of x with mod (div x 10) 10. You can use this with an accumulator that accumulates the value by each time multiplying with 10, so:
everyOther :: Int -> Int
everyOther = go 0
where go a v
| v < 10 = a
| otherwise = go (10*a + mod (div v 10) 10) (div v 100)
If v is thus less than 10, we can return the accumulator, since there is no "other digit" anymore. If that is not the case, we multiply a with 10, and add mod (div v 10) 10 to add the other digit to it, and recurse with the value divided by 100 to move it two places to the right.
We can improve this, as #Daniel Wagner says, by making use of quotRem :: Integral a => a -> a -> (a, a):
everyOther :: Int -> Int
everyOther = go 0
where go a v
| v < 10 = a
| otherwise = let (q, r) = v `quotRem` 100 in go (10*a + r `quot` 10) q
here we thus work with the remainder of a division by 100, and this thus avoids an extra modulo.
I'm trying to make a recursive function which defines division in terms of subtraction. So I have created a new type "DividedResult" to take into account a "divide by zero" case. Do my datatype declaration and function type declaration make sense? I get such errors:
No instance for (Num DividedResult) arising from the literal `0' In the third argument of `go'
Could not deduce (Num DividedResult) arising from a use of `+'
(Probably have to create a Num instance? I have tried, but it doesn't work for me).
Here is my code:
data DividedResult = Result Integer | DividedByZero
dividedBy :: Integer -> Integer -> (DividedResult, Integer)
dividedBy num denom = go num denom 0
where go n d count
| d == 0 = (DividedByZero, n)
| abs n < abs d = (count, n)
| abs n >= abs d && n > 0 && d > 0 = go (n - d) d (count + 1)
| abs n >= abs d && n > 0 && d < 0 = go (n + d) d (count - 1)
| abs n >= abs d && n < 0 && d < 0 = go (n - d) d (count + 1)
| abs n >= abs d && n < 0 && d > 0 = go (n + d) d (count - 1)
The reason you get that error, is because you are trying to return an actual Integer here:
| abs n < abs d = (count, n)
By returning count, an Integer instead of a DividedResult, the compiler thinks you are trying to cast a number into a DividedResult, which is only possible if DividedResult is a Num
In this case, making DividedResult an instance of Num would be overkill; you just need to wrap count:
| abs n < abs d = (Result count, n)
Trying to prove that a sum of positive numbers is positive.
-- some function
variable {w : nat -> int}
-- sum of w's from 0 to i
def sw : nat -> int
| 0 := w 0
| (i+1) := sw i + w (i+1)
-- w is always positive
axiom w_pos : ∀ i : nat, 0 < w i
-- sum of w's is always positive
lemma sw_pos : ∀ i : nat, 0 < sw i // error here
| 0 := w_pos 0
| (i+1) :=
have h₁ : 0 + w (i+1) < sw (i+1), from add_lt_add_right (sw_pos i) (w (i+1)),
have h₂ : 0 < 0 + w (i+1), from add_lt_add_left (w_pos (i+1)) 0,
show 0 < sw (i+1), from lt_trans h₂
On the declaration of sw_pos, Lean complains that it "don't know how to synthesize placeholder context" for sw.
How to resolve this error?
To prove the validity of this valid triple:
{X==U, Y==0, U > 0, N > 0}
while (X > 0) { X = X - N; Y = Y + 1;};
{Y == ⌈U/N⌉}
What is the loop invariant?
I'm working on implementing the Sieve of Sundaram.
The first step is to get a list of Integer's such that:
i, j are Natural Numbers, 1 <= i <= j
i + j + 2*i*j <= n
Here's my function. It's supposed to generate a list of tuples of all (i, j)'s that match the above
restrictions.
numsToRemove :: Integer -> [(Integer, Integer)]
numsToRemove n = [ (i, j) | i <- [1..n], j <- [1..n], i <= j, i >= 1, j >= 1,
i * j + 2*i*j <= n]
But I'm getting non-primes in my answer. Excluding my other work, I think that I'm making a mistake in generating this list of Integers.
Please let me know what I'm doing wrong.
Your function checks for i * j + 2*i*j <= n but your definition asks for i + j + 2*i*j <= n. There is a * that should have been a +.