Zulip Chat Archive

Stream: general

Topic: well-founded recursion on polynomials


Eric Rodriguez (Mar 08 2022 at 12:25):

I'd really like to be able to make this definition:

def derivative_seq : R[X]  list R[X]
| 0 := []
| p := p :: derivative_seq (p.derivative)

but Lean shouts at me in many ways, and I guess understandably so. There's many things wrong with this - firstly, I don't think Lean likes me using 0 as a pattern (and I'm not too sure that .(0) helps - if I do that and turn it into a meta_def, it just turns the whole function into λ p, []). Furthermore, I'd like to use well-founded recursion here - for p ≠ 0, we clearly have that degree (p.derivative) < degree p, but how do I get that p ≠ 0 apart from that if it was, we'd have gone down the first path?

I guess essentially I'm really misunderstanding the equation compiler and maybe forcing it to do things it doesn't want to. Is the correct way to use wf.fix?

Eric Rodriguez (Mar 08 2022 at 12:27):

is this the correct way to do this?

noncomputable def derivative_seq [decidable_eq R[X]] : R[X]  list R[X]
| p := if p  0 then p :: derivative_seq (p.derivative) else []

Eric Wieser (Mar 08 2022 at 12:29):

Another option would be to directly recurse on p.degree

Eric Rodriguez (Mar 08 2022 at 12:30):

hmm, that doesn't seem to well-found properly, this throws an error:

noncomputable def derivative_seq [decidable_eq R[X]] : R[X]  list R[X]
| p := if h : p = 0 then [] else have _ := polynomial.degree_derivative_lt h,
                                 p :: derivative_seq (p.derivative)

Eric Rodriguez (Mar 08 2022 at 12:30):

Eric Wieser said:

Another option would be to directly recurse on p.degree

with a match, you mean?

Eric Wieser (Mar 08 2022 at 12:30):

Probably an auxiliary def

Eric Wieser (Mar 08 2022 at 12:32):

def aux :   polynomial R  list (polynomial R)
| 0 p := []
| (n+1) p := p :: aux n p.derivative

Then use aux p.degree p or similar

Reid Barton (Mar 08 2022 at 12:33):

Why do you need a list?

Eric Rodriguez (Mar 08 2022 at 12:34):

What do you suggest, Reid? I'm trying to implement Budan-Fourier like the Isabelle implementation

Eric Rodriguez (Mar 08 2022 at 12:34):

https://arxiv.org/abs/1811.11093

Eric Wieser (Mar 08 2022 at 12:34):

polynomial.derivative^[n] maybe?

Eric Rodriguez (Mar 08 2022 at 12:37):

I can also just stick that in a list.map, I don't get p :: derivative_seq p' = derivative_seq p automatically but that's ok

Johan Commelin (Mar 08 2022 at 12:37):

But even then, why would you need a list?

Eric Rodriguez (Mar 08 2022 at 12:42):

My understanding of the theorem is that I take the sequence of derivatives, evaluate them at a point, and the sign differences in this sequence are meaningful. The way I calculate sign differences is using a list representation, although also a finsupp could work just as well, thinking about it.

Eric Rodriguez (Mar 08 2022 at 12:43):

It's also far more idiomatic; I've made a function that turns a polynomial into a list and even proving that a monomial's representation was if r = 0 then [0] else r :: list.repeat 0 n was hell

Eric Rodriguez (Mar 08 2022 at 12:44):

I think in Isabelle (or at least from what I got from the paper) they represent polynomials directly as lists, so they don't have to think about all this

Eric Rodriguez (Mar 08 2022 at 12:45):

oh, maybe not:

typedef (overloaded) 'a poly = "{f :: nat ⇒ 'a::zero. ∀⇩∞ n. f n = 0}"

Johan Commelin (Mar 08 2022 at 12:47):

I think you can just work with nat -> R given by n \mapsto (polynomial.derivative^[n] p).eval x.

Johan Commelin (Mar 08 2022 at 12:47):

That sequence will eventually be zero

Johan Commelin (Mar 08 2022 at 12:48):

But you can still count the number of sign differences on the image of finset.range (p.nat_degree + 1).


Last updated: Dec 20 2023 at 11:08 UTC