Zulip Chat Archive

Stream: new members

Topic: Stavan Jain


Stavan Jain (Aug 14 2024 at 13:56):

Hi everyone, my name is Stavan and I'm just about to start my fourth year as an undergraduate at Duke University. I'm majoring in Math and Computer Science and have recently been interested in the paradigm of formalizing mathematics in Lean.

I was trying to define the sequence an=3na_n = 3^{-n} in Lean as below:
def aₙ : ℕ → ℝ := fun (n : ℕ) => 3 ^ (- n : ℝ)

I get the following error message: "failed to compile definition, consider marking it as 'noncomputable' because it depends on 'Real.instPow', and it does not have executable code".

As I understand, the exponentiation function rpow : RRR\R \to \R \to \R is not computable in Lean. Is there a way I can work around this apart from marking it as noncomputable? More generally, it would be helpful if someone could redirect me to a resource that would help me understand the limitations of noncomputable definitions.

Damiano Testa (Aug 14 2024 at 13:58):

For most of the mathematical development, is the computable definitions that are a limitation!

Stavan Jain (Aug 14 2024 at 14:04):

Damiano Testa said:

For most of the mathematical development, is the computable definitions that are a limitation!

In what sense?

Luigi Massacci (Aug 14 2024 at 14:07):

You can work with rationals, that should be computable (if you actively want computability)

Luigi Massacci (Aug 14 2024 at 14:07):

And if you need it real-valued at some point you can cast it at the last second

Luigi Massacci (Aug 14 2024 at 14:14):

Stavan Jain said:

In what sense?

For starters, the "mathematician's" real numbers (i.e. if for you the real numbers are an uncountable set) are inherently uncomputable, so it's hard to to say much of anything about them from a perspective of computation. More in general, computability is a property that takes a lot of effort to preserve, and is quite limiting in what it allows you to do

Eric Wieser (Aug 14 2024 at 14:22):

Luigi Massacci said:

And if you need it real-valued at some point you can cast it at the last second

Or you can define your function over an arbitrary Semifield, so that it works for both Real and Rational

Stavan Jain (Aug 14 2024 at 14:23):

Thank you @Luigi Massacci

Julian Berman (Aug 14 2024 at 14:26):

I think it's usually Kyle who points this out, but just to be sure, note that whether something is noncomputable affects what Lean will evaluate for you -- but it doesn't mean you can't separately calculate the answer via tactics, or prove some answer is the right one, e.g.:

import Mathlib

noncomputable def aₙ :    := fun (n : )  3 ^ (- n : )

-- #eval aₙ 0  -- FAILS

example : aₙ 0 = 1 := by
  dsimp [aₙ]
  simp only [CharP.cast_eq_zero, neg_zero, Real.rpow_zero]

Stavan Jain (Aug 14 2024 at 14:36):

Ah, that's helpful! I assume this is because we have theory about multiplying/exponentiating by 0 for real numbers. Would trying to prove something like example : aₙ 1 = (1/3) := by sorry be futile?

Julian Berman said:

I think it's usually Kyle who points this out, but just to be sure, note that whether something is noncomputable affects what Lean will evaluate for you -- but it doesn't mean you can't separately calculate the answer via tactics, or prove some answer is the right one, e.g.:

import Mathlib

noncomputable def aₙ :    := fun (n : )  3 ^ (- n : )

-- #eval aₙ 0  -- FAILS

example : aₙ 0 = 1 := by
  dsimp [aₙ]
  simp only [CharP.cast_eq_zero, neg_zero, Real.rpow_zero]

Julian Berman (Aug 14 2024 at 14:36):

You should try it!

Damiano Testa (Aug 14 2024 at 14:53):

You may find it easier to work with

noncomputable abbrev aₙ :    := fun (n : )  (1 / 3) ^ n

Note that the exponent is now a natural number and def became abbrev, which basically saves you from having to unfold aₙ everywhere.

Damiano Testa (Aug 14 2024 at 14:54):

The def vs abbrev is a technicality, but the choice of what function you use is very important in formalization and a good choice can save you lots of time down the line, for no mathematical difference.

Stavan Jain (Aug 14 2024 at 15:18):

Julian Berman said:

You should try it!

Thanks! I got it to work:

example : aₙ 1 = (1/3) :=  by
  dsimp [aₙ]
  rw [Nat.cast_one, one_div, Real.rpow_neg_one]

or even

example : aₙ 3 = (1/27) :=  by
  dsimp [aₙ]
  have rpow_three (x : ) : x ^ (3 : ) = x ^ 3 := by
    rw [ Real.rpow_natCast]
    simp only [Nat.cast_ofNat]
  rw [one_div, Real.rpow_neg, rpow_three, inv_inj]
  · linarith
  linarith

However, the second proof relies on the computability of the power function on natural numbers, correct? The first linarith closes the goal 3 ^ 3 = 27

Stavan Jain (Aug 14 2024 at 15:20):

Damiano Testa said:

The def vs abbrev is a technicality, but the choice of what function you use is very important in formalization and a good choice can save you lots of time down the line, for no mathematical difference.

Ah okay. Is (1/3)n(1/3)^ n a better choice than 3n3 ^ {-n} because it avoids negative exponents?

Damiano Testa (Aug 14 2024 at 15:23):

Yes, negative and real.

Damiano Testa (Aug 14 2024 at 15:23):

You can try proving the other lemmas with the new definition and using simp or norm_num.

Damiano Testa (Aug 14 2024 at 15:24):

E.g.

import Mathlib

noncomputable abbrev aₙ :    := fun (n : )  (1 / 3) ^ n

example : aₙ 3 = (1/27) :=  by
  norm_num

Stavan Jain (Aug 14 2024 at 19:52):

Ah, that does indeed make the proofs a lot easier. Thank you @Damiano Testa


Last updated: May 02 2025 at 03:31 UTC