Zulip Chat Archive

Stream: new members

Topic: Complex numbers sums


Gabriel Moise (Apr 12 2021 at 15:10):

Hello! I was playing with some sums over real and complex numbers, but I got stuck at the following:

import data.real.basic
import data.complex.basic

open_locale big_operators

universe u
variables {V : Type u} [fintype V] [decidable_eq V]
variables (r : V  ) (c : V  )

lemma test_lemma :  i : V, (c i * r i) =  i : V, (r i * c i) :=
begin
  have key :  i : V, (c i * r i) = (r i * c i),
  {intro i, exact mul_comm (c i) (r i)},
  simp[key],
end

def test_real :  :=  i : V, r i
def test_complex :  :=  i : V, c i -- definition 'test_complex' is noncomputable, it depends on 'complex.field'

def sum_elems (c : V  ) :=  i : V, c i -- same

def product_elems :  :=  j : V, c j * r j -- same

I was trying to create a function that would do a "dot_product" between a real and a complex vector, but I got an error, and apparently I can't have a definition that, given a complex vector, returns the sum of its elements. The explanation I see is that the part where we prove that the set of complex numbers is a field is noncomputable, but from what I saw (correct me if I'm wrong), this is also the case for the set of real numbers. However, for real numbers everything is fine. Additionally, I could work in a lemma with the sum I wanted to obtain (and I tested it on a simple lemma to see how it behaves) without any complains. What should I do?

Anne Baanen (Apr 12 2021 at 15:11):

Quick answer: you can put noncomputable theory after the imports, then Lean will stop warning you about noncomputability.

Anne Baanen (Apr 12 2021 at 15:13):

You need to warn that a def is noncomputable because normally, Lean produces executable code for a def. For lemmas, it only checks that the lemma proof has the type of the lemma statement.

Anne Baanen (Apr 12 2021 at 15:22):

The reason why it happens to work for reals and not for complex numbers is kind of technical: in principle both test_real and test_complex should be computable, since addition, subtraction and multiplication of real numbers are computable, so are the equivalent operations for complex numbers: there is a computable comm_ring ℝ structure in mathlib (called docs#real.comm_ring). But for complex numbers, there is only a field ℂ structure available, docs#complex.field, and mathlib's division operator is not computable for real or complex numbers. This noncomputability also "infects" the add_comm_monoid ℂ structure used by the summation over V, making it noncomputable too.

Gabriel Moise (Apr 12 2021 at 15:28):

But if I want to continue working with the sum_elems and product_elems definitons, is it ok to make them noncomputable and then carry on using them?

Anne Baanen (Apr 12 2021 at 15:28):

Yes, there should be no problem marking them noncomputable.

Gabriel Moise (Apr 12 2021 at 15:30):

Ultimately, I am trying to work with the eigenvalues of a real-valued matrix, and since they can be complex, my plan is to define eigenvectors as complex and this would imply a (real)matrix-(complex)vector multiplication operation. I don't know if this is a good approach, but might get more experience from it.

Anne Baanen (Apr 12 2021 at 15:32):

That sounds like a good start if you are doing the project to practice. If you want to contribute to mathlib, be sure to check out docs#module.End.has_eigenvector as well, so you don't do too much duplicate work :)

Gabriel Moise (Apr 12 2021 at 15:38):

I consulted that as well, but it seems a little too complicated for me at the moment, as I am not a very experienced mathematician :( . I don't really see how to apply the definition

def eigenspace (f : End R M) (μ : R) : submodule R M :=
(f - algebra_map R (End R M) μ).ker

to my case with f being a matrix (linear transformation) with coefficients in ℝ and μ a complex value. So that's why I wanted to make something more restricted (even though I am using noncomputable to every definition I create :laughing: ), but obviously the best way would be to use the already existing model and build from it.

Yakov Pechersky (Apr 12 2021 at 15:40):

You can interpret the real matrix as being in C, then the types match up

Yakov Pechersky (Apr 12 2021 at 15:41):

Would you rather work with matrix ... or linear_map?

Gabriel Moise (Apr 12 2021 at 15:44):

I am not sure what would be the best option. I already have some work with matrices and I wanted to develop that more with some eigenvalue properties, so that's why I wanted to work with matrices. Can I juggle between them easily/efficiently?

Yakov Pechersky (Apr 12 2021 at 15:46):

docs#matrix.to_lin' and docs#linear_map.to_matrix'

Yakov Pechersky (Apr 12 2021 at 15:46):

So easy interconversion retaining the linear structure

Yakov Pechersky (Apr 12 2021 at 15:48):

And you can use a coe that is a linear_map to express your linear map on R as a linear map on C

Gabriel Moise (Apr 12 2021 at 15:50):

Thank you! I'll see how I can work with those!

Yakov Pechersky (Apr 12 2021 at 15:50):

I'm sure somewhere in mathlib we have the linear_map, or even linear_isometry of the embedding of R into C

Yakov Pechersky (Apr 12 2021 at 15:51):

Then you get your End C C iiuc

Gabriel Moise (Apr 12 2021 at 15:54):

How would a lemma like "Eigenvalues of a symmetric real matrix are real" be stated using linear maps then?

Yakov Pechersky (Apr 12 2021 at 15:57):

for all mu such that End.has_eigenvalue (real_to_complex f) mu, mu.im = 0 or something more neat

Gabriel Moise (Apr 12 2021 at 15:58):

And where does the symmetry come into place?

Yakov Pechersky (Apr 12 2021 at 15:59):

Well, it's a constraint on what f you provide

Yakov Pechersky (Apr 12 2021 at 16:00):

If you're working on End, you might use linear_equiv

Gabriel Moise (Apr 12 2021 at 16:02):

I see, and btw if I have a noncomputable definition test_def, I can't have a command "unfold test_def" I suppose, right?

Yakov Pechersky (Apr 12 2021 at 16:03):

Yes, you can. noncomputable just means that no VM code is generated for that defn

Eric Wieser (Apr 12 2021 at 16:21):

(deleted)

Eric Wieser (Apr 12 2021 at 16:22):

Anne Baanen said:

But for complex numbers, there is only a field ℂ structure available, docs#complex.field,

Citation needed: docs#complex.comm_ring

Eric Wieser (Apr 12 2021 at 16:22):

It sounds like the action problem is that docs#complex.add_comm_monoid is missing

Gabriel Moise (Apr 12 2021 at 17:18):

Is there a way to prove that :

lemma sum_complex_re (x : V  ) : ( i : V, x i).re =  i : V, (x i).re

I was thinking about using the "add_re" lemma, but I don't see how.

Eric Wieser (Apr 12 2021 at 17:28):

Previously that would be linear_map.re.map_sum

Eric Wieser (Apr 12 2021 at 17:28):

But I think docs#linear_map.re got renamed

Eric Wieser (Apr 12 2021 at 17:28):

docs#complex.re_lm?

Gabriel Moise (Apr 12 2021 at 17:31):

And how can it be used for the sum?

Ruben Van de Velde (Apr 12 2021 at 17:35):

You'd need docs#linear_map.map_sum with re_lm as f

Eric Wieser (Apr 12 2021 at 17:36):

complex.re_lm.map_sum I think is the proof of your lemma

Gabriel Moise (Apr 12 2021 at 17:42):

Found it, it was linear_map.re.map_sum, thanks!

Eric Wieser (Apr 12 2021 at 17:51):

Sounds like you're on an old mathlib

Kevin Buzzard (Apr 12 2021 at 21:31):

There's no such thing as a symmetric linear map -- this is a predicate on matrices, ie it depends on the choice of basis

Yakov Pechersky (Apr 12 2021 at 21:35):

You can still phrase this about linear_maps in a round-about way via matrix.to_lin, which does require two explicit bases

Gabriel Moise (Apr 13 2021 at 15:18):

Is there a lemma which states that the sum of nonnegative (real) numbers is 0 iff all the numbers are 0?

Yakov Pechersky (Apr 13 2021 at 15:20):

That's a lemma about a constant function

Yakov Pechersky (Apr 13 2021 at 15:21):

docs#finset.sum_const_zero

Ruben Van de Velde (Apr 13 2021 at 15:22):

That's only one direction of the iff, surely

Yakov Pechersky (Apr 13 2021 at 15:23):

Or docs#finset.sum_subset

Gabriel Moise (Apr 13 2021 at 15:24):

Yeah, I am more interested in the => direction. (sum = 0 => numbers are 0)

Yakov Pechersky (Apr 13 2021 at 15:24):

I don't think the iff is stated anywhere obvious because nonnegative numbers isn't a type.

Yakov Pechersky (Apr 13 2021 at 15:24):

Unless you're working on nnreal

Yakov Pechersky (Apr 13 2021 at 15:25):

Or it is, but I can't guess the name at the moment

Ruben Van de Velde (Apr 13 2021 at 15:25):

docs#finset.sum_eq_zero_iff_of_nonneg ?

Gabriel Moise (Apr 13 2021 at 15:25):

This one looks helpful

Ruben Van de Velde (Apr 13 2021 at 15:29):

docs#finset.sum_eq_zero_iff seems to work on nnreal

Gabriel Moise (Apr 14 2021 at 11:00):

Is there a lemma which states that a polynomial of degree n (with real coefficients) has n (complex) roots?

Anne Baanen (Apr 14 2021 at 11:03):

Probably the easiest: combine docs#polynomial.degree_eq_card_roots and docs#complex.is_alg_closed, via docs#is_alg_closed.splits

Gabriel Moise (Apr 14 2021 at 11:17):

And the homomorphism should be from C to C? I am a little confused about the "splits" part

Johan Commelin (Apr 14 2021 at 11:18):

@Gabriel Moise in general a polynomial only split over a some larger field extension.

Johan Commelin (Apr 14 2021 at 11:19):

So you have to give the ring hom that describes this extension.

Johan Commelin (Apr 14 2021 at 11:19):

But that last lemma that Anne linked to shows that id : C -> C will work, because C is alg. closed (2nd link).

Anne Baanen (Apr 14 2021 at 11:19):

Since your coefficients are real, the specific ring hom will be algebra_map ℝ ℂ.

Johan Commelin (Apr 14 2021 at 11:20):

Good point, I forgot the actual question :face_palm:

Anne Baanen (Apr 14 2021 at 11:22):

Hmm, you'll have to do some rewriting (composing algebra_map ℝ ℂ with the identity) to get this to work. Should we define is_alg_closed.splits : ∀ {R S} (f : R →+* S) (p : polynomial R), p.splits f instead?

Anne Baanen (Apr 14 2021 at 11:23):

That is: keep the definition of is_alg_closed, rename is_alg_closed.splits to is_alg_closed.splits' and add this as a better eliminator.

Johan Commelin (Apr 14 2021 at 11:25):

@Anne Baanen yes, that seems very reasonable

Johan Commelin (Apr 14 2021 at 11:26):

Where I assume S is your preferred letter for algebraically closed fields :grinning:

Anne Baanen (Apr 14 2021 at 11:26):

Ah nevermind, that is literally the next definition docs#polynomial.splits' :P

Anne Baanen (Apr 14 2021 at 11:28):

Wait no, there f goes in the opposite direction.

Johan Commelin (Apr 14 2021 at 11:31):

Lol... I guess we want both

Anne Baanen (Apr 14 2021 at 11:33):

I don't want to call them polynomial.splits' and polynomial.splits'', how about is_alg_closed.splits_domain (the domain of f is alg closed) and is_alg_closed.splits_codomain (the codomain of f is alg closed)?

Gabriel Moise (Apr 14 2021 at 11:38):

I am a little stuck with these two now:

lemma help_split (P : polynomial ) : splits (algebra_map  ) P := sorry

lemma help_algebra_map (P : polynomial ) : multiset.card (map (algebra_map  ) P).roots = multiset.card P.roots := sorry

Kevin Buzzard (Apr 14 2021 at 11:39):

I would imagine that multiset.card P.roots is just the roots of P in the reals, so that second one might not be true for something like x^2+1 right?

Gabriel Moise (Apr 14 2021 at 11:42):

Oh, I see, then this approach doesn't work then?

lemma help_split (P : polynomial ) : splits (algebra_map  ) P := sorry

lemma degree_n_poly_has_n_roots (P : polynomial ) (H_P : P  0) : P.degree = P.roots.card :=
begin
  let i :  →+*  := algebra_map  ,
  have hsplit : splits i P, {exact help_split P},
  rw degree_eq_card_roots H_P hsplit,
  -- Goal : ↑(⇑multiset.card (map i P).roots) = ↑(⇑multiset.card P.roots)
  sorry,
end

Anne Baanen (Apr 14 2021 at 11:48):

Question 1:

lemma help_split (P : polynomial ) : splits (algebra_map  ) P :=
by { rw [ (algebra_map  ).id_comp,  splits_map_iff],
     exact is_alg_closed.splits (P.map (algebra_map  )) }

(soon it will just be := is_alg_closed.splits_codomain _ _).

Anne Baanen (Apr 14 2021 at 11:49):

Indeed, degree_n_poly_has_n_roots as is stated now is not true, because P.roots does not include any complex roots.

Anne Baanen (Apr 14 2021 at 11:51):

PR created: #7187

Gabriel Moise (Apr 14 2021 at 11:51):

I see, thank you very much for the clarifications!

Gabriel Moise (Apr 14 2021 at 12:00):

But if I modify P to be a polynomial over C, the degree_n_poly_has_n_roots would be correct, though I don't know how to continue with that:

lemma degree_n_poly_has_n_roots (P : polynomial ) (H_P : P  0) : P.degree = P.roots.card :=
begin
  let i :  →+*  := algebra_map  ,
  have hsplit : splits i P, {exact help_split P},
  rw degree_eq_card_roots H_P hsplit,
  -- Goal : ↑(⇑multiset.card (map i P).roots) = ↑(⇑multiset.card P.roots)
  sorry,
end

Kevin Buzzard (Apr 14 2021 at 12:02):

Does refl solve it?

Johan Commelin (Apr 14 2021 at 12:05):

dsimp [i], simp [map_id] hopefully.

Eric Wieser (Jul 01 2021 at 19:03):

The original computability problem at the top of this thread will be solved by #8166


Last updated: Dec 20 2023 at 11:08 UTC