Idris won't expand `mult` in proof of exponent law - idris

I'm trying to write a proof that 2^n * 2^m = 2^(n+m) in Idris. Right now I have this:
expLaw : (power 2 n) * (power 2 m) = power 2 (n + m)
expLaw {n=Z} {m} = plusZeroRightNeutral (power 2 m)
expLaw {n=S n'} {m=m'} =
trans (multAssociative 2 (power 2 n') (power 2 m')) $
cong {f=mult 2} $ expLaw {n=n'} {m=m'}
This gives me the error:
When checking an application of function trans:
Type mismatch between
mult 2 (power 2 n' * power 2 m') = mult 2 (power 2 (n' + m')) (Type of cong powExp)
and
mult (mult 2 (power 2 n')) (power 2 m') = plus (power 2 (plus n' m')) (plus (power 2 (plus n' m')) 0) (Expected type)
Specifically:
Type mismatch between
mult 2 (power 2 (n' + m'))
and
plus (power 2 (plus n' m')) (plus (power 2 (plus n' m')) 0)
As far as I can tell, this is essentially saying that it is seeing a 2 * 2^(n+m) where it wants a 2^(n+m) + (2^(n+m) + 0). However, by the definition of mult, the former should trivially reduce to the latter. In particular, the following compiles without problem:
foo : 2 * a = a + (a + 0)
foo = Refl
To me, this indicates that the expansion is working as I would expect. But for some reason, in my implementation of expLaw, the compiler gets stuck. I'm wondering if it might have something to do with the use of mult and plus versus * and +, but I'm not sure. How can I fix this?
Alternatively, if anyone has a better way to implement expLaw I'd be happy to hear it.

It helps to add proofs step by step with let … in … blocks, so you can easily inspect the types. The error occures under trans, so given
expLaw : (power 2 n) * (power 2 m) = power 2 (n + m)
expLaw {n=Z} {m} = plusZeroRightNeutral (power 2 m)
expLaw {n=S n'} {m=m'} =
let prf1 = cong {f=mult 2} $ expLaw {n=n'} {m=m'} in
let prf2 = multAssociative 2 (power 2 n') (power 2 m') in
?hole
> :t hole
m' : Nat
n' : Nat
prf1 : plus (mult (power 2 n') (power 2 m'))
(plus (mult (power 2 n') (power 2 m')) 0) =
plus (power 2 (plus n' m')) (plus (power 2 (plus n' m')) 0)
prf2 : plus (mult (power 2 n') (power 2 m'))
(plus (mult (power 2 n') (power 2 m')) 0) =
mult (plus (power 2 n') (plus (power 2 n') 0)) (power 2 m')
--------------------------------------
hole : mult (plus (power 2 n') (plus (power 2 n') 0)) (power 2 m') =
plus (power 2 (plus n' m')) (plus (power 2 (plus n' m')) 0)
You can see that the order of the equalities prf2 : a = b, prf1 : a = c don't match up with trans : (a = b) -> (b = c) -> a = c. But with a simple sym : (a = b) -> b = a it works. So you almost had it. :-)
…
let prf3 = trans (sym prf2) prf1 in
prf3

Related

Total definition of Gcd in Idris

I am working in a small project with a goal to give a definition of Gcd which gives the gcd of two numbers along with the proof that the result is correct. But I am unable to give a total definition of Gcd. The definition of Gcd in Idris 1.3.0 is total but uses assert_total to force totality which defeats the purpose of my project. Does someone have a total definition of Gcd which does not use assert_total?
P.S. - My codes are uploaded in https://github.com/anotherArka/Idris-Number-Theory.git
I have a version which uses the Accessible relation to show that the sum of the two numbers you're finding the gcd of gets smaller on every recursive call: https://gist.github.com/edwinb/1907723fbcfce2fde43a380b1faa3d2c#file-gcd-idr-L25
It relies on this, from Prelude.Wellfounded:
data Accessible : (rel : a -> a -> Type) -> (x : a) -> Type where
Access : (rec : (y : a) -> rel y x -> Accessible rel y) ->
Accessible rel x
The general idea is that you can make a recursive call by explicitly stating what gets smaller, and providing a proof on each recursive call that it really does get smaller. For gcd, it looks like this (gcdt for the total version since gcd is in the prelude):
gcdt : Nat -> Nat -> Nat
gcdt m n with (sizeAccessible (m + n))
gcdt m Z | acc = m
gcdt Z n | acc = n
gcdt (S m) (S n) | (Access rec)
= if m > n
then gcdt (minus m n) (S n) | rec _ (minusSmaller_1 _ _)
else gcdt (S m) (minus n m) | rec _ (minusSmaller_2 _ _)
sizeAccessible is defined in the prelude and allows you to explicitly state here that it's the sum of the inputs that's getting smaller. The recursive call is smaller than the input because rec is an argument of Access rec.
If you want to see in a bit more detail what's going on, you can try replacing the minusSmaller_1 and minusSmaller_2 calls with holes, to see what you have to prove:
gcdt : Nat -> Nat -> Nat
gcdt m n with (sizeAccessible (m + n))
gcdt m Z | acc = m
gcdt Z n | acc = n
gcdt (S m) (S n) | (Access rec)
= if m > n
then gcdt (minus m n) (S n) | rec _ ?smaller1
else gcdt (S m) (minus n m) | rec _ ?smaller2
For example:
*gcd> :t smaller1
m : Nat
n : Nat
rec : (y : Nat) ->
LTE (S y) (S (plus m (S n))) -> Accessible Smaller y
--------------------------------------
smaller1 : LTE (S (plus (minus m n) (S n))) (S (plus m (S n)))
I don't know of anywhere that documents Accessible in much detail, at least for Idris (you might find examples for Coq), but there are more examples in the base libraries in Data.List.Views, Data.Vect.Views and Data.Nat.Views.
FYI: the implemenation in idris 1.3.0 (and probably 1.2.0) is total, but uses the assert_total function to achieve this.
:printdef gcd
gcd : (a : Nat) ->
(b : Nat) -> {auto ok : NotBothZero a b} -> Nat
gcd a 0 = a
gcd 0 b = b
gcd a (S b) = assert_total (gcd (S b)
(modNatNZ a (S b) SIsNotZ))

type mismatch between m and (minus m 0)

I'm trying to define the dependent type of n-ary functions (built as a tree out of binary and unary functions; I suspect this is isomorphic to the type of (Vect n a) -> a) as an exercise in learning Idris.
While trying to define a function that applies an argument to an n-ary function (producing an (n-1)-ary function) I got a very suspicious error:
Type mismatch between
ArityFn m a (Type of ng)
and
ArityFn (minus m 0) a (Expected type)
Specifically:
Type mismatch between
m
and
minus m 0
here's the code in question, for reference
data ArityFn : Nat -> (ty: Type) -> Type where
Val : (x : ty) -> ArityFn 0 ty
UnaryFn : (ty -> ty) -> ArityFn 1 ty
BinaryFn : (ty -> ty -> ty) -> ArityFn 2 ty
NAryFn : (ty -> ty -> ty) -> (ArityFn n ty) -> (ArityFn m ty) -> ArityFn (n + m) ty
%name ArityFn nf, ng, nh
applyArityFn : a -> (ArityFn n a) -> (LTE 1 n) -> ArityFn (n - 1) a
... (some definitions elided)
applyArityFn x (NAryFn h (UnaryFn f) ng) _ = mkNAryFn h (Val (f x)) ng
is this a bug in the typechecker?
When in doubt, look for the definition of the function which got stuck:
:def minus returns (among other things, modulo some cleanup):
Original definiton:
minus 0 right = 0
minus left 0 = left
minus (S left) (S right) = minus left right
You can see that minus left 0 = left won't hold definitionally because there is a pattern minus 0 right = 0 before. Now, of course both equations return the same result when they happen to coincide but idris doesn't know that.
To get the result you want you can:
either somehow pattern match on m and get minus to reduce now that the head constructor of its first argument is exposed
or rewrite by a proof that minus m 0 = m.

Plus vs S in a function type

The following declaration of vector cons
cons : a -> Vect n a -> Vect (n + 1) a
cons x xs = x :: xs
fails with the error
Type mismatch between
S n
and
plus n 1
while the following vector append compiles and works
append : Vect n a -> Vect m a -> Vect (n + m) a
append xs ys = xs ++ ys
Why type-level plus is accepted for the second case but not for the first. What's the difference?
Why does x :: xs : Vect (n + 1) a lead to a type error?
(+) is defined by induction on its first argument so n + 1 is stuck (because n is a stuck expression, a variable in this case).
(::) is defined with the type a -> Vect m a -> Vect (S m) a.
So Idris needs to solve the unification problem n + 1 =? S m and because you have a stuck term vs. an expression with a head constructor these two things simply won't unify.
If you had written 1 + n on the other hand, Idris would have reduced that expression down to S n and the unification would have been successful.
Why does xs ++ ys : Vect (n + m) a succeeds?
(++) is defined with the type Vect p a -> Vect q a -> Vect (p + q) a.
Under the assumption that xs : Vect n a and ys : Vect m a, you will have to solve the constraints:
Vect n a ?= Vect p a (xs is the first argument passed to (++))
Vect m a ?= Vect q a (ys is the first argument passed to (++))
Vect (n + m) a ?= Vect (p + q) a (xs ++ ys is the result of append)
The first two constraints lead to n = p and m = q respectively which make the third constraint hold: everything works out.
Consider append : Vect n a -> Vect m a -> Vect (m + n) a.
Notice how I have swapped the two arguments to (+) in this one. You would then be a situation similar to your first question: after a bit of unification, you would end up with the constraint m + n ?= n + m which Idris, not knowing that (+) is commutative, would'nt be able to solve.
Solutions? Work arounds?
Whenever you can it is infinitely more convenient to have a function defined using the same recurrence pattern as the computation that happens in its type. Indeed when that is the case the type will be simplified by computation in the various branches of the function definition.
When you can't, you can rewrite proofs that two things are equal (e.g. that n + 1 = S n for all n) to adjust the mismatch between a term's type and the expected one. Even though this may seem more convenient than refactoring your code to have a different recurrence pattern, and is sometimes necessary, it usually is the start of path full of pitfalls.

Struggling with rewrite tactic in Idris

I'm going through Terry Tao's real analysis textbook, which builds up fundamental mathematics from the natural numbers up. By formalizing as many of the proofs as possible, I hope to familiarize myself with both Idris and dependent types.
I have defined the following datatype:
data GE: Nat -> Nat -> Type where
Ge : (n: Nat) -> (m: Nat) -> GE n (n + m)
to represent the proposition that one natural number is greater than or equal to another.
I'm currently struggling to prove reflexivity of this relation, i.e. to construct the proof with signature
geRefl : GE n n
My first attempt was to simply try geRefl {n} = Ge n Z, but this has type Ge n (add n Z). To get this to unify with the desired signature, we obviously have to perform some kind of rewrite, presumably involving the lemma
plusZeroRightNeutral : (left : Nat) -> left + fromInteger 0 = left
My best attempt is the following:
geRefl : GE n n
geRefl {n} = x
where x : GE n (n + Z)
x = rewrite plusZeroRightNeutral n in Ge n Z
but this does not typecheck.
Can you please give a correct proof of this theorem, and explain the reasoning behind it?
The first problem is superficial: you are trying to apply the rewriting at the wrong place. If you have x : GE n (n + Z), then you'll have to rewrite its type if you want to use it as the definition of geRefl : GE n n, so you'd have to write
geRefl : GE n n
geRefl {n} = rewrite plusZeroRightNeutral n in x
But that still won't work. The real problem is you only want to rewrite a part of the type GE n n: if you just rewrite it using n + 0 = n, you'd get GE (n + 0) (n + 0), which you still can't prove using Ge n 0 : GE n (n + 0).
What you need to do is use the fact that if a = b, then x : GE n a can be turned into x' : GE n b. This is exactly what the replace function in the standard library provides:
replace : (x = y) -> P x -> P y
Using this, by setting P = GE n, and using Ge n 0 : GE n (n + 0), we can write geRefl as
geRefl {n} = replace {P = GE n} (plusZeroRightNeutral n) (Ge n 0)
(note that Idris is perfectly able to infer the implicit parameter P, so it works without that, but I think in this case it makes it clearer what is happening)

Understanding recurrence relation

I have this recurrence relation
T(n) = T(n-1) + n, for n ≥ 2
T(1) = 1
Practice exercise: Solve recurrence relation using the iteration method and give an asymptotic running time.
So I solved it like this:
T(n) = T(n-1) + n
= T(n-2) + (n - 1) + n
= T(n-3) + (n - 2) + (n - 1) + n
= …
= T(1) + 2 + … (n - 2) + (n - 1) + n **
= 1 + 2 + … + (n - 2) + (n - 1) + n
= O(n^2)
I have some questions:
1)How I can find asymptotic running time?
**2)At this state of problem T(1) means that there was n that when it was subtracted with a number it gave the result 1, right?
3)What if T(0) = 1 and what if T(2) = 1?
Edit: 4) Why n ≥ 2 is useful?
I need really to understand it for my Mid-Term test
T(n) = T(n-1) + n, for n ≥ 2
T(1) = 1
If T(x) represents the running time:
You have already found the asymptotic running time, O(n^2) (quadratic).
If the relation is changed to T(0) = 1 or T(2) = 1, then the running time is still quadratic. The asymptotic behavior does not change if you add a constant or multiply by a constant, and changing the initial condition only adds a constant to the following terms.
n ≥ 2 is present in the relation so that T(n) is defined at exactly once for every positive n. Otherwise, both lines would apply to T(1). You cannot compute T(1) from T(0) using T(n) = T(n-1) + n. Even if you could, T(1) would be defined in two different (and potentially inconsistent) ways.