Zulip Chat Archive

Stream: new members

Topic: Nth derivative of a function


Icaro Costa (Jan 08 2023 at 22:09):

I want to write a definition Dn that represents the nth derivative in one variable. This is what I'm trying:

import analysis.calculus.deriv
import data.real.basic

/-Function definitions-/
variable (f :  -> )

noncomputable def D : (  )  (  )
  | a := deriv a

noncomputable def Dn :  × (  )  (  )
  | (0, a) := a
  | (1, a) := D a
  | (n+1, a) := Dn (n, a)

I get the error:

failed to prove recursive application is decreasing, well founded relation
  @has_well_founded.r ( × (  ))
    (@prod.has_well_founded  (  ) (@has_well_founded_of_has_sizeof  nat.has_sizeof)
       (@has_well_founded_of_has_sizeof (  ) (default_has_sizeof (  ))))
Possible solutions:
  - Use 'using_well_founded' keyword in the end of your definition to specify tactics for synthesizing well founded relations and decreasing proofs.
  - The default decreasing tactic uses the 'assumption' tactic, thus hints (aka local proofs) can be provided using 'have'-expressions.
The nested exception contains the failure state for the decreasing tactic.
nested exception message:
default_dec_tac failed
state:
Dn :  × (  )    ,
n : ,
a :   
 prod.lex has_lt.lt (λ (a₁ a₂ :   ), false) (n, a) (n + 1, a)

I don't understand this error, what does using_well_founded means?

Sky Wilshaw (Jan 08 2023 at 22:10):

Your function currently takes an argument of type ℕ × (ℝ → ℝ). I'd recommend switching this to a curried function style, where your function type is ℕ → (ℝ → ℝ) → (ℝ → ℝ).

Sky Wilshaw (Jan 08 2023 at 22:11):

Then I believe the error will disappear.

Sky Wilshaw (Jan 08 2023 at 22:11):

Are you familiar with functional programming in other languages?

Yaël Dillies (Jan 08 2023 at 22:12):

You will find docs#nat.iterate useful

Icaro Costa (Jan 08 2023 at 22:12):

Sky Wilshaw said:

Are you familiar with functional programming in other languages?

This is my first time working with this sort of language

Sky Wilshaw (Jan 08 2023 at 22:13):

I'd recommend looking at this page in Functional Programming in Lean for more information, but basically:

Sky Wilshaw (Jan 08 2023 at 22:14):

Suppose your function takes multiple inputs, say, a and b, and outputs c. It's usually easier to define it as a function which takes an input a and spits out a second function, which takes an input b and outputs c.

Sky Wilshaw (Jan 08 2023 at 22:14):

So you'd write the type as a -> (b -> c), or more concisely, a -> b -> c.

Sky Wilshaw (Jan 08 2023 at 22:15):

All of Lean's syntax is built to accommodate this programming style, including things like function applications, where you just write f a b instead of f(a)(b).

Sky Wilshaw (Jan 08 2023 at 22:16):

To answer your original question, Lean will check every definition you write to make sure that it doesn't infinitely loop. The in-built method for determining this wasn't able to verify that Dn doesn't infinitely loop, because it used the comparatively more complicated type ℕ × (ℝ → ℝ). If instead you use just , then pass (ℝ → ℝ) as another parameter afterwards, it's easier to figure out that it doesn't infinitely loop.

Sky Wilshaw (Jan 08 2023 at 22:17):

using_well_founded is a way to basically tell Lean a proof that your function doesn't loop infinitely.

Icaro Costa (Jan 09 2023 at 00:33):

Sky Wilshaw said:

To answer your original question, Lean will check every definition you write to make sure that it doesn't infinitely loop. The in-built method for determining this wasn't able to verify that Dn doesn't infinitely loop, because it used the comparatively more complicated type ℕ × (ℝ → ℝ). If instead you use just , then pass (ℝ → ℝ) as another parameter afterwards, it's easier to figure out that it doesn't infinitely loop.

Using your explanation, I managed to write this instead:

def Dn : ()  (  )  (  )
  | 0 := id
  | 1 := D
  | a := Dn a-1

The last error is gone, but now I receive a message saying "rec_fn_macro only allowed in meta definitions". What is that?

Mario Carneiro (Jan 09 2023 at 00:36):

that's an error reporting bug, but that definition is not even well founded, it loops infinitely for n >= 2

Mario Carneiro (Jan 09 2023 at 00:37):

you most likely wanted to write Dn (a-1) instead of Dn a - 1, but this won't work either, because we can't prove in that context that a is nonzero. You can write it with a +1 instead though:

def Dn : ()  (  )  (  )
  | 0 := id
  | 1 := D
  | (a+1) := Dn a

Icaro Costa (Jan 09 2023 at 00:39):

Mario Carneiro said:

you most likely wanted to write Dn (a-1) instead of Dn a - 1, but this won't work either, because we can't prove in that context that a is nonzero. You can write it with a +1 instead though:

def Dn : ()  (  )  (  )
  | 0 := id
  | 1 := D
  | (a+1) := Dn a

Somehow it still yields the same error

Mario Carneiro (Jan 09 2023 at 00:39):

I think the error message is about a missing noncomputable

Mario Carneiro (Jan 09 2023 at 00:40):

most likely D is a noncomputable def

Icaro Costa (Jan 09 2023 at 00:40):

Huh, that seems to have worked. What does the noncomputable does exactly?

Icaro Costa (Jan 09 2023 at 00:41):

Is it that I cannot get a number from it from #eval?

Mario Carneiro (Jan 09 2023 at 00:41):

it says that lean shouldn't attempt to compile it so you can't use it in #eval

Icaro Costa (Jan 09 2023 at 00:41):

Ah got it. Thanks!

Sky Wilshaw (Jan 09 2023 at 01:20):

Note that Dn is not actually the right definition, you probably want D \circ Dn a or something in the (a+1) case.

Junyan Xu (Jan 09 2023 at 06:20):

You can simply write

import analysis.calculus.deriv
noncomputable def Dn (n : ) (f :   ) :    := deriv^[n] f

F^[n] is notation for docs#nat.iterate

Mark Andrew Gerads (Jan 09 2023 at 06:22):

iterated_deriv might be what is wanted here.
https://leanprover-community.github.io/mathlib_docs/analysis/calculus/iterated_deriv.html#iterated_deriv


Last updated: Dec 20 2023 at 11:08 UTC