Zulip Chat Archive

Stream: Is there code for X?

Topic: by decide implies Computable


Bjørn Kjos-Hanssen (Sep 16 2024 at 23:44):

[The suggestion below is wrong as pointed out downthread by Daniel Weber, however a modified version is still open, see below...]

Would this be a suitable additional axiom for Lean in the context where we do not open Classical?
By "suitable" I mean, nobody is likely to be able to prove it or disprove it, but it is presumably true in the intended model of Lean.

import Mathlib.Computability.Partrec

axiom church_turing (f :   ) [DecidablePred (fun x : Fin 2   => f (x 0) = (x 1))] :
  Computable f

For example, this is how one then proves that x => 2*x is computable:

Try this: exact church_turing fun k  2 * k

Edward van de Meent (Sep 17 2024 at 06:36):

I think the fact that Classical exists causes this to not be true?

Daniel Weber (Sep 17 2024 at 06:57):

You mean if we don't have Classical.choice as an axiom?

Bjørn Kjos-Hanssen (Sep 17 2024 at 07:02):

Yes... or is there a way to express "Decidable in a such a way that by decide will actually decide it"?

Daniel Weber (Sep 17 2024 at 07:04):

Note that equality on is always decidable, so your axiom is just that every function is computable

Daniel Weber (Sep 17 2024 at 07:04):

I don't know much constructive logic, but that should still be false there

Bjørn Kjos-Hanssen (Sep 17 2024 at 07:11):

Daniel Weber said:

Note that equality on is always decidable, so your axiom is just that every function is computable

Not true since you also need to find the value of f. There are uncountably many f and only countably many algorithms...

Daniel Weber (Sep 17 2024 at 07:15):

What do you mean?

import Mathlib.Computability.Partrec

axiom church_turing (f :   ) [DecidablePred (fun x : Fin 2   => f (x 0) = (x 1))] :
  Computable f

lemma all_computable (f :   ) : Computable f := church_turing f
-- or equivalently
-- lemma all_computable (f : ℕ → ℕ) : Computable f := @church_turing f (fun x ↦ instDecidableEqNat (f (x 0)) (x 1))

-- 'all_computable' depends on axioms: [church_turing, propext, Quot.sound]
#print axioms all_computable

Bjørn Kjos-Hanssen (Sep 17 2024 at 07:34):

Daniel Weber said:

What do you mean?

import Mathlib.Computability.Partrec

axiom church_turing (f :   ) [DecidablePred (fun x : Fin 2   => f (x 0) = (x 1))] :
  Computable f

lemma all_computable (f :   ) : Computable f := church_turing f
-- or equivalently
-- lemma all_computable (f : ℕ → ℕ) : Computable f := @church_turing f (fun x ↦ instDecidableEqNat (f (x 0)) (x 1))

-- 'all_computable' depends on axioms: [church_turing, propext, Quot.sound]
#print axioms all_computable

Thanks, that's surprising! Okay but my question remains about predicates for which by decide or #eval can be used ... do they have a name?

Daniel Weber (Sep 17 2024 at 07:37):

You mean functions which are/aren't marked noncomputable? Note that you can't talk about that in Lean itself, because that's a property of the implementation, not the function.

Bjørn Kjos-Hanssen (Sep 17 2024 at 07:44):

Well we do talk about it in some sense when we write by decide...

Daniel Weber (Sep 17 2024 at 07:51):

by decide is equivalent to exact of_decide_eq_true rfl, it just takes a docs#Decidable and checks if it's defeq to true. However, defeq-ness is not a mathematical property, it just a property of Lean's implementation.

Bjørn Kjos-Hanssen (Sep 17 2024 at 08:02):

Ah but then isn't it a subclass of the computable functions, even if exactly which subclass it is depends on implementation? If so, it could make sense to postulate that these functions are in fact Computable

Daniel Weber (Sep 17 2024 at 08:03):

It's also not just a property of the function, it's also a property of the implementation:

import Mathlib

def obviously_true : Prop :=  n : ,  m > n, Prime m  Prime (m + 2)

section

noncomputable instance inst1 : Decidable obviously_true := Classical.propDecidable _

example : obviously_true := by
  /-
  tactic 'decide' failed for proposition
  obviously_true
  -/
  decide

end

section

theorem obvious : obviously_true := sorry

instance inst2 : Decidable obviously_true := .isTrue obvious

example : obviously_true := by
  decide

end

example : inst1 = inst2 := Subsingleton.elim _ _

Johan Commelin (Sep 17 2024 at 08:07):

@Yannick Forster can probably give some advice here. He gave a talk in Bonn about (amongst other things) a synthetic approach to (un)decidability. But I don't feel confident commenting about details.

Benedikt Peterseim (Sep 17 2024 at 18:53):

Similar comment: I’ve heard people talk about how “all functions are computable” holds in the internal language of the so-called effective topos. I’m not quite sure how Lean’s type theory precisely relates to the internal language of toposes (with universes perhaps?), but people seem to treat them as if they were essentially the same. Cf. Johan’s “condensed type theory”. So by that intuition your axiom should be consistent to add.

Bjørn Kjos-Hanssen (Sep 17 2024 at 19:16):

@Benedikt Peterseim Here's a sense in which not "all functions are computable":

import Mathlib.Computability.Partrec
import Mathlib.Computability.Halting

example : ¬ ( f : Nat.Partrec.Code  Bool, Computable f) := by
  have Q :=  @ComputablePred.halting_problem 2
  contrapose Q; simp_all
  unfold ComputablePred
  use (by apply Classical.decPred)
  apply Q

Johan Commelin (Sep 17 2024 at 19:19):

That proof relies on classical axioms.

Bjørn Kjos-Hanssen (Sep 17 2024 at 19:24):

OK... well, the question is whether there is a way to have
"not all functions are Computable"
and at the same time postulate
"all functions decided by of_decide_eq_true rfl are Computable."

Johan Commelin (Sep 17 2024 at 19:28):

I think that might be possible with a tactic.

Johan Commelin (Sep 17 2024 at 19:28):

But I'm not capable of writing it.

Bjørn Kjos-Hanssen (Sep 17 2024 at 19:30):

I don't mean to prove
"all functions decided by of_decide_eq_true rfl are Computable"
just to be able to state it in Lean?

Mario Carneiro (Sep 17 2024 at 19:35):

no you can't state that, this is a quantified definitional equality hypothesis, which doesn't exist in lean

Mario Carneiro (Sep 17 2024 at 19:35):

what you could prove by a tactic is "all functions expressible as closed terms are Computable"

Bjørn Kjos-Hanssen (Sep 17 2024 at 19:39):

How do you state
"all functions expressible as closed terms are Computable"?

Mario Carneiro (Sep 17 2024 at 19:40):

you can't

Mario Carneiro (Sep 17 2024 at 19:40):

you can state "Function f is Computable" where f is a concrete function given to the tactic as an Expr

Bjørn Kjos-Hanssen (Sep 17 2024 at 19:44):

If such a tactic were available, would it give a way to automatically prove e.g.

Computable fun k  k * k + 1

(without having to mess with the specifics of how Computable is defined)?

Mario Carneiro (Sep 17 2024 at 19:44):

yes

Mario Carneiro (Sep 17 2024 at 19:44):

writing such a tactic would be very challenging though

Mario Carneiro (Sep 17 2024 at 19:45):

because you basically have to compile all of lean down to turing machines or partial recursive functions or something

Bjørn Kjos-Hanssen (Sep 17 2024 at 19:51):

#goals

Violeta Hernández (Sep 17 2024 at 21:49):

A simpler approach is just to show that certain large classes of functions are computable, and that computability is closed under certain wide ranges of operations. "Every primitive recursive function is computable" should already get you a lot of the way.

Bjørn Kjos-Hanssen (Sep 17 2024 at 23:01):

True although when proving e.g. that if f is Computable then `fun k : ℕ => f k + 1 is Computable we are already beyond primitive recursive functions in a way.

Bjørn Kjos-Hanssen (Sep 18 2024 at 01:19):

Would the fact that there are only countably many computable functions be worth adding to Mathlib? Here's my proof of it:

import Mathlib.Computability.PartrecCode

instance : Countable {f :  →.  | Nat.Partrec f} := by
  rw [Set.ext <| fun f => @Nat.Partrec.Code.exists_code f]
  apply @Function.Injective.countable
    ({f |  c, Nat.Partrec.Code.eval c = f}) Nat.Partrec.Code _ (fun f => Classical.choose f.2)
  intro f g h
  apply SetCoe.ext
  rw [ Classical.choose_spec f.2, Classical.choose_spec g.2]
  tauto

instance : Countable {f :    | Computable f} :=
  @Function.Injective.countable {f :    | Computable f} {f :  →.  | Nat.Partrec f} _
    (fun f => f.val, Partrec.nat_iff.mp f.2)
    fun _ _ h => SetCoe.ext <| PFun.lift_injective <| (Subtype.mk.injEq _ _ _ _)  h

Violeta Hernández (Sep 18 2024 at 03:44):

Yes! If we have some way to state there's only countably many computable numbers, that would be great too.

Bjørn Kjos-Hanssen (Sep 18 2024 at 06:15):

Would need to define "computable real number" first, it seems... :thinking:

Yannick Forster (Sep 18 2024 at 09:10):

Johan Commelin said:

Yannick Forster can probably give some advice here. He gave a talk in Bonn about (amongst other things) a synthetic approach to (un)decidability. But I don't feel confident commenting about details.

I'm a bit late to the party. In Lean without classical axioms, "all functions are computable" is a fine axiom. In Coq, we at some point worked towards a tactic doing computability proofs automatically. https://drops.dagstuhl.de/entities/document/10.4230/LIPIcs.ITP.2019.17 it worked well-ish. In principle, it should be possible to do something similar if not better for Lean, if somebody wants to chat about that I'd be happy to -- but it would be a major project

Kevin Buzzard (Sep 18 2024 at 09:28):

Related: Martin Hairer once pointed out to me that without AC it's consistent that all functions are measurable, so there could in theory be a measurability tactic which just checks that the function was defined constructively and then says yes :-) However I would imagine that fun_prop deals with this situation more effectively.

Floris van Doorn (Sep 18 2024 at 09:31):

I'm not sure how useful that observation is, given that almost anything involving the real numbers is not constructive in Mathlib.

Yannick Forster (Sep 18 2024 at 09:33):

Kevin Buzzard said:

Related: Martin Hairer once pointed out to me that without AC it's consistent that all functions are measurable, so there could in theory be a measurability tactic which just checks that the function was defined constructively and then says yes :-) However I would imagine that fun_prop deals with this situation more effectively.

Probably one could even write a tactic which given any constructively defined function constructs a proof of measurability -- for the same reason why one can write one that gives computability proofs

Kevin Buzzard (Sep 18 2024 at 09:33):

His actual observation was that you could also assume countable dependent choice and still have a model with all functions measurable

Daniel Weber (Sep 18 2024 at 09:56):

This just implies that you can't construct a function which is provably immeasurable, I don't see why it implies that all functions you can construct are provably measurable

Kevin Buzzard (Sep 18 2024 at 09:59):

Yes I guess you're right. I'll tell Hairer that his papers have holes in.

Bjørn Kjos-Hanssen (Sep 19 2024 at 01:00):

Violeta Hernández said:

Yes! If we have some way to state there's only countably many computable numbers, that would be great too.

https://github.com/leanprover-community/mathlib4/pull/16935

Daniel Weber (Sep 19 2024 at 03:06):

Talking about computable numbers, I guess there's a negative to the division by zero convention—it means that the field structure on the computable numbers isn't computable

Daniel Weber (Sep 19 2024 at 03:17):

What can be done computability for them? NormedCommRing and StrictOrderedCommRing?

Bjørn Kjos-Hanssen (Sep 19 2024 at 03:33):

Would you define a computable real number as the equivalence class of a computable Cauchy sequence with a computable modulus of convergence?

Daniel Weber (Sep 19 2024 at 03:41):

That sounds reasonable, yes

Daniel Weber (Sep 19 2024 at 03:46):

Another option is to define an Real.IsComputable predicate

Violeta Hernández (Sep 21 2024 at 11:52):

Daniel Weber said:

Talking about computable numbers, I guess there's a negative to the division by zero convention—it means that the field structure on the computable numbers isn't computable

But the set of computable reals is still a field!

Mario Carneiro (Sep 21 2024 at 11:55):

that depends on what you mean by "field"

Mario Carneiro (Sep 21 2024 at 11:55):

it's only closed under division by values apart from 0

Mario Carneiro (Sep 21 2024 at 12:00):

Given a turing machine M, define a real number as 2^-n if M halts in n steps, and 0 if it does not halt. This is a computable real number because you can get an n-digit approximation of it by running M for n steps. But the inverse of this real number is not computable unless you can decide the halting problem for M.

Daniel Weber (Sep 21 2024 at 12:02):

Assuming em either M halts (and then you can compute this number), or it doesn't, and then the number is 0 which is computable, so the inverse is always computable

Mario Carneiro (Sep 21 2024 at 12:03):

in this example you don't actually know whether it is even legal to take the inverse unless you solve the halting problem for M. If I tell you it is not equal to 0, then classically we can say that the inverse is well defined and there exists a turing machine outputting the integral value but we don't know what it is

Daniel Weber (Sep 21 2024 at 12:09):

The inverse is computable if you're promised that the input number is non-zero, i.e. the function inv : (x : Computable) -> x ≠ 0 -> Computable is computable, but there's no computable function inv0 : Computable -> Computable which agrees with it

Daniel Weber (Sep 21 2024 at 12:11):

Just compute the number with increasing accuracy until you separate it from zero and then it's fairly simple

Mario Carneiro (Sep 21 2024 at 12:20):

you still need em for that argument

Mario Carneiro (Sep 21 2024 at 12:21):

the proper intuitionistic version uses "apart from 0" instead of "not equal to 0"

Mario Carneiro (Sep 21 2024 at 12:21):

i.e. there exists an n such that |x| >= 2^-n

Mario Carneiro (Sep 21 2024 at 12:22):

but assuming em, there is a lean-computable function Computable -> x != 0 -> Computable

Daniel Weber (Sep 21 2024 at 12:22):

Mario Carneiro said:

you still need em for that argument

Only for the termination proof, not the computation

Bjørn Kjos-Hanssen (Sep 21 2024 at 18:20):

By the way, I noticed that Computable.ite is missing in Partrec.lean, maybe worth adding?

theorem ite {c :   Bool} {f :   } {g :   }
    (hc : Computable c) (hf : Computable f)
    (hg : Computable g) : Computable fun a => if (c a) then (f a) else (g a)
     := Computable.of_eq (Computable.cond hc hf hg)
      (fun n => by rw [Bool.cond_eq_ite_iff])

Mario Carneiro (Sep 21 2024 at 18:26):

it's basically the same as cond though with that spelling

Mario Carneiro (Sep 21 2024 at 18:26):

which btw can be written as bif a then b else c

Bjørn Kjos-Hanssen (Sep 21 2024 at 18:32):

Right. I just noticed there's Primrec.ite so then I expected to find Computable.ite as well... but had to prove it instead

Mario Carneiro (Sep 21 2024 at 18:36):

I mean that you are not taking a propositional argument so there is no advantage to using if there, you can just use bif instead

Bjørn Kjos-Hanssen (Sep 21 2024 at 18:47):

Ah, I see. How about this one instead: #17039

Violeta Hernández (Sep 22 2024 at 03:49):

Mario Carneiro said:

that depends on what you mean by "field"

Well, the set is closed under all the operations, isn't it? It's just that you can't necessarily decide what they evaluate as

Daniel Weber (Sep 22 2024 at 03:54):

I think Mario's point is that constructively it's only closed to division by values apart from zero, not by values not equal to it

Violeta Hernández (Sep 24 2024 at 09:59):

That makes sense. But "the computable numbers are a field" is a claim I've definitely seen before.

Violeta Hernández (Sep 24 2024 at 10:01):

Like, the function ℕ → ℝ where f n = 0 if the nth turing machine (under some enumeration) halts and f n = 1 otherwise, only takes on computable values, even if it's not itself computable.

Violeta Hernández (Sep 24 2024 at 10:01):

Something similar should happen for division of computable numbers

Violeta Hernández (Sep 24 2024 at 10:01):

And that's a result I think would be worth having in Mathlib.

Daniel Weber (Sep 24 2024 at 10:06):

Violeta Hernández said:

Like, the function ℕ → ℝ where f n = 0 if the nth turing machine (under some enumeration) halts and f n = 1 otherwise, only takes on computable values, even if it's not itself computable.

In this analogy I think what happens is that constructively you can't prove that

Luigi Massacci (Sep 24 2024 at 10:37):

Violeta Hernández said:

That makes sense. But "the computable numbers are a field" is a claim I've definitely seen before.

Because paper math Field allows to leave division by zero undefined, unlike lean

Mario Carneiro (Sep 24 2024 at 12:12):

I think the result of the discussion above is that the computable reals are a field, but the computable reals are not a computable field unless you make some subtle tweaks to the definition

Bjørn Kjos-Hanssen (Sep 24 2024 at 22:24):

You also run into the problem that given a program/code c it is quite hard to tell whether it represents a Cauchy sequence with computable modulus of convergence (something like second iteration of the halting problem, 0'').
Apparently the characterization is that you need a high Turing degree,

aT0a'\ge_T 0''

(By the way I wrote a whole file about many-one reducibility only to finally discover @Mario Carneiro 's reduce.lean...
looking forward to checking that out though.)

Mario Carneiro (Sep 24 2024 at 22:52):

did I write something on reducibility?

Mario Carneiro (Sep 24 2024 at 22:53):

file#Computability/Reduce seems that way

Bjørn Kjos-Hanssen (Sep 24 2024 at 22:53):

I guess you're the second author. File

Mario Carneiro (Sep 24 2024 at 22:53):

I think I reviewed this but did not write most of it

Mario Carneiro (Sep 24 2024 at 22:55):

Bjørn Kjos-Hanssen ☀️ said:

You also run into the problem that given a program/code c it is quite hard to tell whether it represents a Cauchy sequence with computable modulus of convergence

But generally you won't be asked to determine this in the first place. Obviously determining whether a given real is computable is also hard

Mario Carneiro (Sep 24 2024 at 22:56):

I think you would just bake into the definition that a computable real is one for which there is a turing machine which spits out approximations with a fixed modulus of convergence (e.g. 2^-n)

Bjørn Kjos-Hanssen (Sep 24 2024 at 23:13):

Usually in computability theory we say a structure A is computable if it has domain Nat and all functions and relations on A are computable.

Bjørn Kjos-Hanssen (Sep 24 2024 at 23:19):

There's no computable structure with operations +, * (of course, not the usual such operations on Nat) that's isomorphic to the computable reals (by the paper I linked to)

Mario Carneiro (Sep 25 2024 at 00:13):

isomorphic to the computable reals sounds like it is asking for too much, in particular it will be a surjection onto the computable reals and not a bijection because equality is not decidable

Mario Carneiro (Sep 25 2024 at 00:15):

but also having domain Nat sounds like too much to ask for, this is a total function between subtypes of Nat

Mario Carneiro (Sep 25 2024 at 00:16):

i.e. it is only required to have sensible behavior on inputs satisfying a condition, not necessarily decidable, but all such inputs have to produce elements in the target satisfying the condition

Mario Carneiro (Sep 25 2024 at 00:17):

This is the natural notion you get out of the type theoretic reading of computability

Mario Carneiro (Sep 25 2024 at 00:21):

I think I basically disagree with the definition in that presentation, or at least, it's not sufficiently considering what it means to have computable functions on types that are not Nat

Bjørn Kjos-Hanssen (Sep 25 2024 at 00:22):

Maybe we can call your notion "computable relative to the domain" or "given the domain"

Mario Carneiro (Sep 25 2024 at 00:28):

what would it mean for a function to be computable not relative to its own domain?

Mario Carneiro (Sep 25 2024 at 00:30):

This is just like the observation that xR{0}1/x:R{0}x\in\mathbb{R}\setminus\{0\}\mapsto 1/x : \mathbb{R}\setminus\{0\} is a continuous function

Bjørn Kjos-Hanssen (Sep 25 2024 at 00:31):

I mean, the indicator function for the halting set, restricted to the halting set, is computable given its domain, i.e., it is the constant function 1 on its domain. But its graph is not computable in the ambient space.

Mario Carneiro (Sep 25 2024 at 00:31):

relative to a larger domain, it is a partial function and therefore not computable but partial recursive, but that's a different function we're talking about

Mario Carneiro (Sep 25 2024 at 00:33):

Bjørn Kjos-Hanssen ☀️ said:

I mean, the indicator function for the halting set, restricted to the halting set, is computable given its domain, i.e., it is the constant function 1 on its domain. But its graph is not computable in the ambient space.

I think it is fair to say that the halting problem is decidable when restricted to turing machines that halt

Bjørn Kjos-Hanssen (Sep 25 2024 at 00:35):

For a computable field we should (acc. to common definition) be able to write down multiplication and addition tables showing how the elements interact... but for the computable reals you don't know what the elements are and you can't.

Mario Carneiro (Sep 25 2024 at 00:38):

For addition and multiplication I fail to see the issue?

Mario Carneiro (Sep 25 2024 at 00:39):

You can calculate approximations within any given precision given TMs for the inputs which provide approximations within any given precision

Mario Carneiro (Sep 25 2024 at 00:40):

I mean it's not really a table so much as a functional program but you can write it down

Mario Carneiro (Sep 25 2024 at 00:41):

this is how exact real arithmetic libraries work

Bjørn Kjos-Hanssen (Sep 25 2024 at 00:42):

Suppose I wanted to know if there's a square root of 2 in a given field. In a computable field I can fix my 1 and then 2=1+1 and then check all the x's one at a time. If there's an x with x^2=2 I eventually find it.
In a field where I don't know the domain, I can't do that [of course in the computable reals we know sqrt(2) exists but I think you see my point]

Mario Carneiro (Sep 25 2024 at 00:44):

no I don't think I do see your point. Enumeration is not the way to construct computable reals

Mario Carneiro (Sep 25 2024 at 00:44):

because it implies that "checking" is even a thing you can do

Mario Carneiro (Sep 25 2024 at 00:45):

What you are showing is that a particular bad algorithm doesn't work, that doesn't show that no algorithm exists

Mario Carneiro (Sep 25 2024 at 00:45):

and indeed one does exist, you can implement square root on computable reals too

Bjørn Kjos-Hanssen (Sep 25 2024 at 01:12):

Okay how about this.... the structure Q:=(Q,+,)Q := (\mathbb Q,+,\cdot) is computable in the sense that there exist computable functions ff and gg on N\mathbb N such that QQ is isomorphic to (N,f,g)(\mathbb N,f,g). In that same sense, the structure (ComputableReals,+,)(\text{ComputableReals},+,\cdot) is not computable. That's an interesting difference (to some people, part of the time...) but what you want to call it is of course a sociological question.

Bjørn Kjos-Hanssen (Sep 25 2024 at 01:21):

(N\mathbb N could be replaced by {0,1}\{0,1\}^* (finite strings) or your favorite nice discrete type here)

Mario Carneiro (Sep 25 2024 at 14:33):

that definition explicitly excludes any type Q which is not bijective with Nat, and even for those that are denumerable it doesn't allow for types that have complex well formedness conditions and/or have no natural bijection to Nat

Mario Carneiro (Sep 25 2024 at 14:36):

There are plenty of examples like "the strings accepted by regular language LL" which, even if they are denumerable, would result in a bijection so complex that the asymptotic complexity of basic operations is thrown completely off

Mario Carneiro (Sep 25 2024 at 14:37):

which is why I argue that this is the wrong definition

Bjørn Kjos-Hanssen (Sep 28 2024 at 20:11):

How hard would it currently be to prove this kind of thing, i.e., basic computability facts in non-Nat types?

import Mathlib.Computability.PartrecCode
import Mathlib.Computability.Halting
import Mathlib.Computability.Primrec

def get_part (σ : List Bool) (k : ) : Part Bool := σ.get? k

example : Partrec₂ get_part := sorry

Mario Carneiro (Sep 28 2024 at 20:28):

There are plenty of such proofs in Computability.Partrec

Mario Carneiro (Sep 28 2024 at 20:30):

Note that your function is actually the composition of a primitive recursive function yielding Option Bool and the coercion from Option A to Part A, which is probably proved in there although I forget

Mario Carneiro (Sep 28 2024 at 20:30):

I'm pretty sure get? is proved primrec

Mario Carneiro (Sep 28 2024 at 20:31):

oh yes this is the composition of docs#Computable.ofOption and docs#Primrec.list_get?

Bjørn Kjos-Hanssen (Sep 28 2024 at 20:58):

Thanks! Sometimes, I search but I don't read...

example : Partrec₂ get_part := by
  apply Computable.ofOption
  apply Computable.list_get?

Last updated: May 02 2025 at 03:31 UTC