Zulip Chat Archive
Stream: Equational
Topic: non-computable non-non-computables?
Cody Roux (Oct 17 2024 at 16:00):
Silly lean question; can def
s not marked with noncomputable
actually be non-computable?
Shreyas Srinivas (Oct 17 2024 at 16:06):
noncomputable
lean defs are ones that use an axiom (usually choice). So their meaning is "you are using a theorem that says you get a data object of your type, but doesn't really tell you how to pick this object". Non-noncomputable
defs have to be total and provably terminating, so I don't see how you can encode a non-computable function in it.
Joachim Breitner (Oct 17 2024 at 16:11):
Fair point, so the last bullet may already be given.
Alex Meiburg (Oct 17 2024 at 16:47):
Shreyas Srinivas said:
noncomputable
lean defs are ones that use an axiom (usually choice). So their meaning is "you are using a theorem that says you get a data object of your type, but doesn't really tell you how to pick this object". Non-noncomputable
defs have to be total and provably terminating, so I don't see how you can encode a non-computable function in it.
Defs that aren't noncomputable don't actually have to be terminating, that's a common misconception. This is due to how partial functions work in Lean. They exist, and the guarantee is just that they don't violate the type safety, so I can't have a partial function that returns a {x:Nat // And (IsSquare x) (Prime x)}
, since there's no data of that type. But I can have a define a partial function that returns how many steps an (arbitrary, possibly non-halting) Turing machine takes to halt, and prove that this is what it computes. This doesn't compromise any safety because the mere existence of this information doesn't let me prove False.
And, this data can then be used in a later definition that isn't partial
, there wouldn't be any external indicator that this function doesn't terminate.
Shreyas Srinivas (Oct 17 2024 at 16:51):
I am completely ignoring partial
since one can't prove anything about them
Shreyas Srinivas (Oct 17 2024 at 16:51):
In the context of the discussion, I think Joachim was trying to prove something about the implication graph
Shreyas Srinivas (Oct 17 2024 at 16:54):
But yeah it is new to me that you can plug in a partial def into a non-partial one
Shreyas Srinivas (Oct 17 2024 at 16:55):
And still prove anything with this def
Joachim Breitner (Oct 17 2024 at 17:17):
Once we have https://github.com/leanprover/lean4/issues/3119 we can even have (some) genuinely non-terminating functions and still do all the proofs we want about them.
Mario Carneiro (Oct 18 2024 at 00:55):
Cody Roux said:
Silly lean question; can
def
s not marked withnoncomputable
actually be non-computable?
Yes, it's actually trivial to do so:
partial def choice {α} : Nonempty α → α := choice
Mario Carneiro (Oct 18 2024 at 01:06):
We can even formally prove it using mathlib:
import Mathlib.Computability.Halting
partial def choice {α} : Nonempty α → α := choice
open Nat.Partrec
def haltingFunction (c : Code) : Bool :=
@decide (Code.eval c 0).Dom <| choice <| Classical.instNonemptyDecidable _
theorem haltingFunction_not_computable : ¬Computable haltingFunction :=
fun h => ComputablePred.halting_problem 0 ⟨_, h⟩
Shreyas Srinivas (Oct 18 2024 at 01:59):
What's the decision procedure for classical.instNonEmptyDecidable?
Cody Roux (Oct 18 2024 at 03:24):
it's a pattern match on the excluded middle, which itself is proven using choice
Cody Roux (Oct 18 2024 at 03:25):
I'm sad that noncomputable
isn't as "sticky" as I thought, I'm not entirely sure why partial
isn't.
Mario Carneiro (Oct 18 2024 at 04:32):
What non-noncomputable
actually means is that the lean compiler can generate code for the definition. Because there is no assumption that the code be terminating, it is always possible to trivially implement any axiom
via looping on every input; it's a "courtesy" that this is not done and instead you get a compilation error if you try to call Classical.choice
in your program, because this is presumably more useful than just wasting CPU cycles.
Mario Carneiro (Oct 18 2024 at 04:33):
The reason partial
is not a viral marker is because it's not really marking the partiality, it's marking the opaqueness. A partial
definition is not provably equal to its unfolding
Mario Carneiro (Oct 18 2024 at 04:35):
You can of course implement a metaprogram to check for transitive usage of opaques or partial definitions; see link and the transitive links
Cody Roux (Oct 18 2024 at 15:32):
Ok, so either we need to do this check, or "promise" not to use partial
in the "final end-to-end theorem" definition.
Mario Carneiro (Oct 18 2024 at 16:17):
sorry, I am missing the context here. In what way do you think this relates to the final theorem?
Mario Carneiro (Oct 18 2024 at 16:17):
I didn't think computability (in the mathematical sense) was on the agenda
Alex Meiburg (Oct 18 2024 at 16:28):
I'm not even sure what that would mean here. We're proving theorems, not providing a calculation. Surely we're not aiming to prove everything constructively (i.e. without using the law of excluded middle).
Vlad Tsyrklevich (Oct 18 2024 at 16:48):
The final calculation is trying to prove statements like A=>B OR NOT (A=>B) so LEM is somewhat of a hinderance there
Cody Roux (Oct 18 2024 at 17:47):
We're trying to say: here is a complete, concrete graph of all implications and non-implications. No need to stare at it, it's huge, but trust us it is both complete and concretely given.
Cody Roux (Oct 18 2024 at 17:48):
If we just say "there exists such a graph" then perhaps people might be less than impressed, since it's easy to prove it exists.
Cody Roux (Oct 18 2024 at 17:49):
This happens all the time in classification problems.
Sébastien Gouëzel (Oct 18 2024 at 17:51):
Using choice or LEM to prove things about whether some implications are true or false does not change anything to the concreteness of the graph, which is completely explicit here.
Cody Roux (Oct 18 2024 at 17:52):
I know that, but does the casual reader know this? How do they know it?
Alex Meiburg (Oct 18 2024 at 18:12):
I see. You'd like to see some final result that's something like
/-- The implication graph, as an adjacency matrix --/
def doesImply (eqA eqB : Fin 4695) : Bool := < ... something computable ... >
theorem doesImply_correct (eqA eqB : Fin 4695) : doesImply eqA eqB \iff ↔ (Equation eqA → eqB) := by
< ... proof of correctness ... >
and that way, anyone who wants to see that the project is complete, would just have to verify that (1) doesImply_correct
doesn't depend on sorryAx
, and (2) that doesImply
is a computable function.
And the concern is that doesImply
could just be defined in terms of e.g. whether a particular Turing machine halts or not, without being marked noncomputable, and then we could have cheated and "skipped" the whole project.
Mario Carneiro (Oct 18 2024 at 20:05):
I think the right way to present this is something like "here is a concrete list of implications and non-implications, and here is a proof that the transitive closure of these generates the whole graph"
Mario Carneiro (Oct 18 2024 at 20:05):
"oh and here's a function if you want to query parts of it"
Joachim Breitner (Oct 18 2024 at 20:58):
Mario Carneiro said:
I think the right way to present this is something like "here is a concrete list of implications and non-implications, and here is a proof that the transitive closure of these generates the whole graph"
That list will be large and possibly generated by a tactic, so the user cannot just eyeball it to see that it really is concrete (and not produced with Classical.choose
), hence the musing of whether there is a more declarative way of saying “this function or this data is concrete/computable/whatever”, besides #print
.
Mario Carneiro (Oct 18 2024 at 21:58):
It should be specified by some actually explicit list together with some closure algorithm which may do more than just implication chaining but also duals and I don't know what else
Eric Wieser (Oct 18 2024 at 22:24):
Mario Carneiro said:
We can even formally prove it using mathlib:
This sounds like a nice result for the Counterexamples
directory
Eric Wieser (Oct 18 2024 at 22:27):
regarding the completeness of the graph, could the statement be something like
def theRawData : Matrix (Fin _) (Fin _) Bool := read_matrix% "implications.txt"
theorem as_closure : theRawData = closureOf (someSmallerData) := sorry
theorem : theRawData i j \iff implies i j := by
rw [as_closure]
sorry
Eric Wieser (Oct 18 2024 at 22:27):
Then you just need to trust read_matrix%
, which is hopefully very trivial
Mario Carneiro (Oct 18 2024 at 22:29):
the trouble is that this formulation is very likely to crash lean
Mario Carneiro (Oct 18 2024 at 22:29):
because theRawData
is an object with 22 million entries
Mario Carneiro (Oct 18 2024 at 22:30):
maybe it would be okay if you encoded it as a bitvector in a string literal or bignum? but even then you'll be stuck trying to prove anything about it without an explosion in term size
Eric Wieser (Oct 18 2024 at 22:34):
22 million bits is only 2.76 megabytes, so storing it as a bitvector and proving facts about it via halving it 25 times could work
Eric Wieser (Oct 18 2024 at 22:34):
Maybe you need ofReduceBool for this to work
Mario Carneiro (Oct 18 2024 at 22:41):
never underestimate lean's ability to use more memory than a napkin calculation would suggest :skull:
Amir Livne Bar-on (Oct 19 2024 at 11:00):
Alex Meiburg said:
I can have a define a partial function that returns how many steps an (arbitrary, possibly non-halting) Turing machine takes to halt, and prove that this is what it computes. This doesn't compromise any safety because the mere existence of this information doesn't let me prove False.
Can't you define a proof sequence of False using this method? With functions conclusion : ProofSeq -> Prop
and embed : (seq : ProofSeq) -> (term : conclusion seq)
? Or even if such embedding is not possible in Lean, it would prove that first-order logic formalized in Lean is inconsistent?
Joachim Breitner (Oct 19 2024 at 11:13):
Eric Wieser said:
22 million bits is only 2.76 megabytes, so storing it as a bitvector and proving facts about it via halving it 25 times could work
That’s what I am experimenting in https://github.com/teorth/equational_theories/pull/636 with, zulip thread #Equational > A final end-to-end theorem in Lean
Alex Meiburg (Oct 19 2024 at 12:48):
Amir Livne Bar-on said:
Can't you define a proof sequence of False using this method? With functions `conclusion : ProofSeq -> Prop` and `embed : (seq : ProofSeq) -> (term : conclusion seq)`? Or even if such embedding is not possible in Lean, it would prove that first-order logic formalized in Lean is inconsistent?
Sorry, I should say, "it computes how many steps it takes to halt, if it halts; otherwise it returns -1". That was implied in my head (because Lean has a number of functions that do something similar of returning junk "if something never happens") but I should have been more explicit.
No, it's not something that implies it's inconsistent.
Amir Livne Bar-on (Oct 19 2024 at 14:13):
This presumably requires choice
though? So we can detect such non-computable definitions by their axioms
Amir Livne Bar-on (Oct 19 2024 at 14:20):
Oh I see, there's also the partial
loophole, so no need for choice
Mario Carneiro (Oct 19 2024 at 14:56):
Note that the partial
loophole is secretly using choice
Mario Carneiro (Oct 19 2024 at 14:57):
I mean, that should be pretty obvious because it gives you a value with the same type as Classical.choice
Mario Carneiro (Oct 19 2024 at 14:59):
partial def foo : α → α := foo
#print axioms foo -- 'foo' does not depend on any axioms
partial def bar : Nonempty α → α := bar
#print axioms bar -- 'bar' depends on axioms: [Classical.choice]
Mario Carneiro (Oct 19 2024 at 15:05):
Here's the secret definition they don't want you to know:
partial def bar : Nonempty α → α := bar
open Lean
run_meta -- fun {α} a => Classical.ofNonempty
let some (.opaqueInfo c) := (← getEnv).find? `bar | failure
logInfo c.value
Amir Livne Bar-on (Oct 19 2024 at 17:03):
So here
https://leanprover.zulipchat.com/#narrow/channel/458659-Equational/topic/non-computable.20non-non-computables.3F/near/477706720
item (2) would be a statement that doesImply does not depend on AoC
Amir Livne Bar-on (Oct 19 2024 at 17:13):
That is, assuming that the DB constructed by equational_result doesn't depend on the axioms used by the theorems
Amir Livne Bar-on (Oct 19 2024 at 17:18):
I guess the greedy construction can be done without choice, so we don't actually need it in the proofs yet
Last updated: May 02 2025 at 03:31 UTC