infix notation in Lean - lean

Is there an infix notation that would allow to rewrite those proofs
example (h₀ : a ≤ b) (h₁ : b < c) (h₂ : c ≤ d) (h₃ : d < e) :
a < e := lt_trans (lt_of_lt_of_le (lt_of_le_of_lt (h₀) h₁) h₂ ) h₃
example (h₀ : a ≤ b) (h₁ : b < c) (h₂ : c ≤ d) (h₃ : d < e) :
a < e := by
{ apply lt_trans,
{apply lt_of_lt_of_le,
{apply lt_of_le_of_lt, apply h₀, apply h₁}
, apply h₂},
apply h₃
}
more naturally as
example (h₀ : a ≤ b) (h₁ : b < c) (h₂ : c ≤ d) (h₃ : d < e) :
a < e := ((h₀ `lt_of_le_of_lt` h₁) `lt_of_lt_of_le` h₂) `lt_trans` h₃

You can use Lean's dot notation to make an infix version of the argument, for example
example (h₀ : a ≤ b) (h₁ : b < c) (h₂ : c ≤ d) (h₃ : d < e) :
a < e := (h₀.trans_lt h₁).trans (h₂.trans_lt h₃)
What's going on here is that the type of h₀ is le a b (in the has_le namespace), so h₀.trans_lt means le.trans_lt h₀, and you can see in order.basic in mathlib that le.trans_lt is just an abbreviation for lt_of_le_of_lt.

Related

about the use of "case of" in Haskell

I think case of is quite straight forward, as i come from more imperative languages.
Nevertheless, i have encountered a Kata where one of the solutions by another user, confuses me about the use of case and Data.List (sort)
import Data.List (sort)
isTriangle :: Int -> Int -> Int -> Bool
isTriangle a b c =
case sort [a,b,c] of
[min, middle, max] -> (min + middle) > max
By definition, 3 segments can make a triangle if the condition a + b > c is met for the 3 permutations of [a,b,c] so, something more straight forward (my answer) would be:
isTriangle :: Int -> Int -> Int -> Bool
isTriangle a b c = a + b > c && b + c > a && a + c > b
My question is, in the case above, how is the case of testing that condition for the 3 combinations?
Imagine that a b and c are ordered from small to large, then the algorithm tests that a + b > c, which is what the first implementation checks.
If we know that a < b < c, and a + b > c holds, then we know that a + c > b holds. Indeed: a + c > a + b > c > b, hence a + c > b holds because a + b > c holds. Furthermore b + c > a + b > c > a holds, and thus b + c > a holds as well.
This thus means that checking if it holds for a known minimum, maximum and value in between, the two other equations are implied.
What the case … of does here is sorting the list [a, b, c] and unpacking the sorted list in min, middle and max, it is thus a tool that is used to assign the smallest value to min, the largest value to max and the remaining value to middle. A where … or let … in … is probably more elegant, for example:
isTriangle :: Int -> Int -> Int -> Bool
isTriangle a b c = (min + middle) > max
where [min, middle, max] = sort [a, b, c]

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

Haskell, Local definition and variables, confused :/

f0 :: Int -> Int -> Int -> Int
f0 a b c = x a b - x a c - x b c
where x b a = a + b
Can someone explain me how the functions knows what to do when it gets to the...
where x b a = a + b
... statement? Does it just translate to something like this?
f0 a b c = (a + b) a b - (a + b) a c - (a + b) b c
[...] or is it just that the "x" is just another functions which takes two variables and add them [...]
Exactly. x b a = a + b is a function definition (that happens to have local scope). f0 0 0 1 = x 0 0 - x 0 1 - x 0 1. – duplode
In some other pseudo language this will look like this.
int function fo(int a, int b, int c){
int function x(int a, int b){
return a + b;
}
return x(a,b) - x(a,c) - x(b,c)
}
The way you have put it as a question,
f0 a b c = (a + b) a b - (a + b) a c - (a + b) b c
it looks like inline substitution like C macros. It is not simple code substitution. It is more like inline function. X is a function which gets called.

Proving property of recursive function

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?

Resources