Proving property of recursive function - lean

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?

Related

Write a function that lists numbers from n to m by k number of steps. If the step size is negative list them in descending order

Implement the interval2 :: Int -> Int -> Int -> [Int] function,that lists numbers from the first parameter to the third parameter, the stepping's size is the second parameter. Using [n..m], [n,k..m] or [n..] is prohibited.
For example:
interval2 1 1 10 == [1,2..10]
interval2 10 1 0 == [10,11..0]
interval2 10 (-1) 0 == [10,9..0]
interval2 1 2 10 == [1,3..10]
interval2 10 2 0 == [10,12..0]
interval2 0 (-2) (-10) == [0,(-2)..(-10)]
interval2 1 (-1) 10 == [1,0..10]
interval2 0 (-10) (-1000) == [0,(-10)..(-1000)]
So far, I've managed to write some cases, but they didn't do the job very well.
interval2 x y z | x < z && y > 0 = [x] ++ interval2 (x+y) y z
| x < z && y < 0 = [x] ++ interval2 (x-y) y z
| x > z && y > 0 = [x] ++ interval2 (x-y) y z
| x > z && y < 0 = [x] ++ interval2 (x+y) y z
| x == z || x > z = [z]
There are basically two cases when you should emit a new value:
if x <= z and y > 0; and
if x >= z and y < 0.
In both cases that means the list contains x as first element and should recurse on the interval with x+y. In case none of these conditions are not met, then we have reached the end of the list.
This thus means that the function looks like:
interval2 x y z
| (x <= z && y > 0) || (x >= z && y < 0) = …
| otherwise = …
where I leave implementing … as an exercise.
Naming is important. When learning, naming is very important.
What is x? What is y? What is z? Are all of them the same, conceptually?
No, as the exercise describes it, it is
interval2 :: Int -> Int -> Int -> [Int]
interval2 from stepSize to =
this already gets you half way there towards the solution. Yes it does.
Or actually, you have a contradiction. According to the title of your post, it is
interval2b :: Int -> Int -> Int -> [Int]
interval2b from numSteps to =
But in any case, solving the first one first, you seem to get lost in the multitude of tests. Instead of doing all of them in one function, why not do a test to decide which of several functions to use to do the job; then write each of those functions being already able to assume certain things, namely those which we've tested for:
interval2 from stepSize to
| stepSize > 0 = increasing from
| stepSize < 0 = decreasing from
| otherwise = []
where
increasing from
| from
and now it is easy to see which test to perform here, isn't it?
> to = []
| otherwise = from : increasing ....
decreasing from
| from
and similarly here.
.........
..................
I hope this helps you manage this complexity so you'll be able to complete this code yourself.

Is there a way to call a function recursively from tactic mode or from match expressions in Lean?

Attempt #1:
def sget' {α : Type} {n : ℕ} (i : ℕ) {h1 : n > 0} {h2 : i < n} (s: sstack α n) : α :=
begin
cases n with n0 nn,
begin
have f : false, from nat.lt_asymm h1 h1,
tauto,
end,
induction s,
cases s_val,
begin
have : stack.empty.size = 0, from #stack_size_0 α,
tauto,
end,
cases i with i0 ri,
exact s_val_x,
exact sget' (pred i) s_val_s,
end
Attempt #2:
def sget' {α : Type} {n : ℕ} (i : ℕ) {h1 : n > 0} {h2 : i < n} (s: sstack α n) : α :=
match i, s with
| 0, ⟨stack.push x s, _⟩ := x
| i, ⟨stack.push _ s, _⟩ := sget' (pred i) ⟨s, _⟩
| _, ⟨stack.empty, _⟩ := sorry -- just ignore this
Lean in both cases throws unknown identifier sget' error. I know that I can call sget' recursively from ehh pattern guards (not sure how they are properly called), but is there any way to do something like that with tactics and/or match expressions?
You can do recursive calls if you use the equation compiler
def map (f : α → β) : list α → list β
| [] := []
| (a :: l) := f a :: map l
Otherwise you should use induction tactic or one of the explicit recursor functions (like nat.rec).

Dafny. Prove that all values from an interval appear in seq

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.)

How to pattern match different ways depending on a particular input?

I have a function:
closeTo61 :: Tactic
closeTo61 s P2 h d e b
| cs + ps < 53 = 0
| cs + ps == 61 = 100 -- Best case
| numWaysToScoreN (61 - (cs + ps)) h b == 0 = 0 -- Worst case
| numWaysToScoreN (61 - (cs + ps)) h b == 1 = 50 -- Strong case
| numWaysToScoreN (61 - (cs + ps)) h b == 2 = 70 -- Very Strong case
| numWaysToScoreN (61 - (cs + ps)) h b >= 3 = 90 -- Extremely Strong case
where
ps = scoreDom d e b
(_,cs) = s
closeTo61 s P1 h d e b
| cs + ps < 53 = 0
| cs + ps == 61 = 100
| numWaysToScoreN (61 - (cs + ps)) h b == 0 = 0
| numWaysToScoreN (61 - (cs + ps)) h b == 1 = 50
| numWaysToScoreN (61 - (cs + ps)) h b == 2 = 70
| numWaysToScoreN (61 - (cs + ps)) h b >= 3 = 90
where
ps = scoreDom d e b
(cs,_) = s
The only reason I've done this with two bindings for each possible input of the second argument is because in the where block the cs is pattern matched differently depending on this input.
Is there a way to do this using only one binding and checking the second input inside the where block in order to use the correct pattern?
You could instead do
closeTo61 s p h d e b
| cs + ps < 53 = 0
| ...
where
cs = chooseByP p s
chooseByP P1 = fst
chooseByP P2 = snd
Although, since you only use s and p to determine which element of s to use, why have them as separate arguments here?
closeTo61 cs h d e b
| ...
where
ps = scoreDom d e b
closeTo61' s p = closeTo61 (chooseByP p s)
You can move the pattern match into the where block where you define cs:
closeTo61 s p h d e b
...
where cs = case p of P1 -> fst s; P2 -> snd s
If you do this a lot (and, since you defined a type for P1 and P2, you might be), I would extract this logic into a more meaningful helper function:
component P1 (x, _) = x
component P2 (_, x) = x
Then you can do
closeTo61 s p h d e b
...
where cs = component p s

Stack overflow in my recursive function

Code is here , when i call numberOf 3 or numberOf integer>2 im getting this error ERROR - C stack overflow . My code should change numbers between 2^(n-2) (2^n)-1 for n>2 to Binary and check if is there consecutive 0 or not . If is there dont count and if there isnt +1 .
numberOf :: Integer -> Integer
numberOf i = worker i
worker :: Integer -> Integer
worker i
| (abs i) == 0 = 0
| (abs i) == 1 = 2
| (abs i) == 2 = 3
| otherwise = calculat (2^((abs i)-2)) ((2^(abs i))-2)
calculat :: Integer -> Integer -> Integer
calculat ab bis
| ab == bis && (checker(toBin ab)) == True = 1
| ab < bis && (checker(toBin ab)) == True = 1 + (calculat (ab+1) bis)
| otherwise = 0 + (calculat (ab+1) bis)
checker :: [Integer] -> Bool
checker list
| list == [] = True
| 0 == head list && (0 == head(tail list)) = False
| otherwise = checker ( tail list)
toBin :: Integer -> [Integer]
toBin n
| n ==0 = [0]
| n ==1 = [1]
| n `mod` 2 == 0 = toBin (n `div` 2) ++ [0]
| otherwise = toBin (n `div` 2) ++ [1]
Tests :
numberOf 3 Answer:(5)
numberOf 5 (13)
numberOf 10 (144)
numberOf (-5) (13)
The problem lies with your definition of calculat. You have the cases of ab == bis and ab < bis, but the only place you call calculat is from worker with the arguments 2^(abs i - 1) and 2^(abs i - 2). Since the first number (ab) will always be larger than the second (bis), checking for ab < bis is pretty silly. In your otherwise condition you then increment ab, ensuring that this function will never terminate. Did you instead mean otherwise = calculat ab (bis + 1)?
You could also clean your code up substantially, there are many places where you've done things the hard way, or added unnecessary clutter:
-- Remove worker, having it separate from numberOf was pointless
numberOf :: Integer -> Integer
numberOf i
| i' == 0 = 0
| i' == 1 = 2
| i' == 2 = 3
-- Lots of unneeded parentheses
| otherwise = calculat (2 ^ (i' - 1)) (2 ^ i' - 2)
-- Avoid writing the same expression over and over again
-- define a local name for `abs i`
where i' = abs i
calculat :: Integer -> Integer -> Integer
calculat ab bis
-- Remove unneeded parens
-- Don't need to compare a boolean to True, just use it already
| ab == bis && checker (toBin ab) = 1
| ab < bis && checker (toBin ab) = 1 + calculat (ab + 1) bis
-- 0 + something == something, don't perform unnecessary operations
| otherwise = calculat (ab + 1) bis
-- Pattern matching in this function cleans it up a lot and prevents
-- errors from calling head on an empty list
checker :: [Integer] -> Bool
checker [] = True
checker (0:0:_) = False
checker (_:xs) = checker xs
-- Again, pattern matching can clean things up, and I find an in-line
-- if statement to be more expressive than a guard.
toBin :: Integer -> [Integer]
toBin 0 = [0]
toBin 1 = [1]
toBin n = toBin (n `div` 2) ++ (if even n then [0] else [1])
In calculat in case ab == bis but checker returns false you cant return from the function.
How about:
| ab >= bis && (checker(toBin ab)) == True = 1
| ab < bis && (checker(toBin ab)) == True = 1 + (calculat (ab+1) bis)
| otherwise = 0 + (calculat (ab+1) bis)
| ab >= bis = 0
| ab < bis == True = 0 + (calculat (ab+1) bis)
| otherwise = 0 + (calculat (ab+1) bis)

Resources