Hacker News new | past | comments | ask | show | jobs | submit login
Sometimes all functions are continuous (2006) (andrej.com)
60 points by lelf on Jan 11, 2020 | hide | past | favorite | 43 comments



The article is a slow burn with a hilariously clickbait title but damn, those are some fascinating and significant consequences.

> An interesting question comes to mind: which programming features, apart from the ones we mentioned above, allow us to program [computably continuous integer streams]? In terms of Haskell, the same question is which monads allow us to program [these streams]?

> Can we do it without any extra features and use just “pure” functional programming?

> If by pure functional programming we understand a functional programming language with natural numbers, booleans and recusive definitions, also known as PCF, the answer is no. The proof of this uses denotational semantics and domain theory, and I will not go into it now. You may entertain yourself by trying and failing to define [computably continuous integer streams] in pure Haskell or ML, i.e., no side effects, no exceptions, no mutable store, no parallelism, no monads.

> ... The lesson is for those “experts” who “know” that all reasonable models of computation are equivalent to Turing machines. This is true if one looks just at functions from N to N. However, at higher types, such as the type of our function m, questions of representation become important, and it does matter which model of computation is used.

It takes a hit on the trend that was in vogue in early 2010s to do AI and metaphysics on top of Kolmogorov Complexity, Solmonoff Induction, information physics... people took the Turing Equivalence as a carte blanche to say whatever willy-nilly thing you want about the (potentially) computable nature of reality without being informed by more naturalistic methods.

This is harshed even further given that these information-theoretic arguments often used non-computable notions.


I'm not making much sense of that article. It's rejecting both the mathematical definition of continuity, and also wants to compute with infinite real numbers, which is just not realistic to computers and languages. So the author ends up with a lot of absurd results.


That's because the author is using constructive mathematics (i.e. computable analysis instead of standard real analysis). It is true that all computable functions are continuous. Likewise discontinuous real functions aren't computable.

The continuum hypothesis is tangentially related to this topic and makes for fun reading.


>In fact, no finite amount of computation will guarantee that we will be able to tell whether x=0 or x>0

Hmm, I'm still stuck at this assertion. Why can we not assume the number is finite?

If we assume an infinitely long number takes an infinite amount of time to read, can we not also assume it must take an infinite amount of time to write? If we only have finite time, can we not assume all numbers given to the function in that time are finite?


Yeah, I'm also stuck here.

The article seems to say that, because you can't produce an upper bound to the amount of time the sgn function will take to run (for all possible inputs), sgn isn't a function. But then... isn't it the same for every single other function?

I think the article is conflating "given a fixed amount of time, one can find an input for which the function will take longer to run" with "the function takes infinite time". The later isn't true: for any given input, no matter how big, one can compute a time such that the function will finish in that time; in other words, the function always finishes, in finite time, for every possible input, no matter how large.

It's possible we're both confused, I suppose. :-)


Here's the thing: the "discrete vs continuous" most people were taught is wrong. Discrete is [can always be construed as] continuous. Only infinite things can be discontinuous.

State is finite but time is countably infinite for our purposes, so we model infinite/unbounded things with programs that can run arbitrary long.

Finally, this abstract math stuff is in fact a really good UI point that most programmers miss. In non "real time" applications, you should aim to be able to dynamically tradeoff tardiness and richness; e.g. a fancy diagram that is rendered at low res and then higher res. Likewise all your caches should be evictable under memory pressure. Computing should feel fluid.

It's a pity most people only paleolithic state machine math or terminating thing math. This falsely implies that "real world programs" which hardly ever terminate are beyond theory, or that the smartypants thing to do is break them down into little terminating programs and some big spooky event loop whateverthefuck (browser, apache, framework du jour, etc etc.). Build codata out of codata!


How would you turn f(x != 1) = 0, f(1) = (has no value) to be continuous?

Because it sounds like you’re simply redefining the terms. At which point you might as well be using “Spork”. Because, defining a new system has zero impact on a different system.


1. You are talking about partial functions, that is a separate concern.

2. Behold https://en.wikipedia.org/wiki/Discrete_space . Topologies define continuinity, and here is a discrete topology.

3. With e.g. probability measures / expected values, which unify "discrete" and "continuous" statistics, you'll notice that there's lots of rules that are trivially obeyed in the discrete case, but take some care in the "continuous" case. For example, not ever set can have a measure in the latter but can in the former. This directly relates to discrete things being trivial to deem continuous. It's also a useful to define coarser topologies / event sigma-algebras in the finite case to better understand the issues are the unavoidable in the infinite cases. We only make the discrete discontinuous in that last "artificial" exercise.


I believe that the function you just defined is already continuous. It's not defined at 1 so checking its continuity doesn't make sense there, and at every other point it's clearly continuous because it's constant. Points that are arbitrarily close to 1 are still continuous because the intervals around 1 are open.


In calculus f(x) = x/x - 1 is not continuous at 1 based on the initial definitions. Moving to fixed-point arithmetic the idea of limits gets odd, but the function still needs a definition for that input.


I would say the continuity isn't just defined at that point... I very much agree that one can't affirmatively say that the function is continuous at that point. Btw. I guess you meant to say f(x) = (x - 1)/(x - 1).

However, let's ignore that; the problem disappears if we define f(x ) = 1 at x = 1, and f(x) = 0 elsewhere.

In standard analysis that function would be discontinuous at that point.

I'm not sure about implications in the OP's kind of analysis. Would the existence of m(1) imply that there exist some smallest input that is larger than 1, that would make difference in output? Same for the largest input that is smaller than 1.


You handle continuity in discrete spaces through topology. A function is continuous for a (really, two) given topology if the inverse images of open sets are open sets.


That specific function can take infinite time to decide whether the input x belongs in the case x < 0, x = 0 or x > 0. The problem manifests itself if we allow x to be a true real number. As you surely know, real numbers may have infinite amount of digits after the point, and if we get a real 0.00000000000... as the input, we must continue inspecting it, until we can be sure about which case it belongs to. But because that real might contain infinite amount of information, we might never finish!


I disagree, how interesting. :-)

I presume that you're allowing finite time execution of the equality-to-zero operation (I.e., a function that says if a number is equal to zero). If you don't, I suppose one would conclude (by applying the same arguments, whatever they are) that neither can a function that, say, adds numbers or does similarly trivial operations finish in finite time, in which case this distinction of finite- vs infinite-runtime functions isn't very interesting.

Any number that isn't zero and that starts with a zero (at the left of the dot), will always have a finite number of zero digits after the point. In other words, the only number that has a zero at the left of the dot (i.e., of the form 0.xyz...) that has an infinite number of zero decimals is zero itself.

I guess where we disagree is in this claim: "As you surely know, real numbers may have infinite amount of digits after the point". The only real numbers with this property are the integers. Every other real number has to have a finite number of zeros.


Here's a more practical definition than "a stream of digits". A computable real representing the real number x is a program that takes as input a rational ϵ>0 and produces as output a rational number within ϵ of x. That is, it produces approximations to x to any desired level of precision.

Every rational q is computable: λϵ.q

The sum of two computable reals, x and y, is computable: λx,y.λϵ.x(ϵ/2)+y(ϵ/2)

You can show the absolute value function is computable: λx.λϵ.|x(ϵ)|

So there are many trivial continuous functions like addition that are computable.

But the discontinuous function f(x)=1 if x=0, f(x)=0 otherwise, is not computable.


A program that takes an integer n and outputs the n'th digit of the number it represents is a finite representation of an infinite stream of digits.


But this is begging the question. The author uses the definition that numbers have infinite decimals, and all you are allowed to do is ask for decimal n to find out a number. You can never grasp the full number, since you are given a finite amount of time (compute) to discover an infinite sequence of decimals.

From that definition, it's quite obvious that everything you compute has to be continuous, because you are never sure of what other decimals may be coming up, so whatever you compute has to be close enough.

That sounds more like an argument that representing numbers that way is not particularly useful since you can't do much with them (you can't even provide an equality operator).


A constructive response is that the ability to examine a real number to arbitrary precision is already highly idealized. In the real world you will quickly exhaust your ability to measure a real quantity to ever higher precision.

> you can't even provide an equality operator

If you are given two rods, there is no way to tell if the two rods are of the same length.


I'm not sure I'm following you. I'm also not arguing for or against the results here. I'm just giving you the background to understand the author's point; it's not something they just came up with, it's been under study for quite a while in constructivist mathematics.

I also don't really think you're using the right definition of computable here. You make it sound as though we're estimating, or truncating uncomputable numbers to make them computable when you say:

> From that definition, it's quite obvious that everything you compute has to be continuous, because you are never sure of what other decimals may be coming up, so whatever you compute has to be close enough.

It's not about being close enough or estimating, they're categorically different things. You can't obtain an uncomputable number, even by estimating, to any meaningful precision with a finite amount of time. So what are you saying here?


You may like the whole list of constructive gems and stones then: http://math.andrej.com/category/gems-and-stones/ :)

As a sampler, the following are all constructively false (ie. imply the law of excluded middle)

* Every finite set can be enumerated without repetitions

* A subset of a finite set is finite

* The intersection of finite sets is finite


Note that these results rely on a technical definition of set that is rather abstract mathematically, in a way programers may find amusing. It defines a set as a potentially infinite list with potential duplicates, from which we can observe that some lists cannot be deduplicated in finite time, making certain operations that are easy on computer science sets not always possible on computer science lists.

For example, is A a subset of B={0}, if all you know about A is that it is a Java iteratable that returns 0 for the first 10^3000 elements you examine?


It's a bit unclear, also the conclusion. However most definitions of continuity are just covering real functions. I remember my math prof stating that there are also continuous functions on the natural numbers (N->N), IIRC n -> n^2 would be an example. Given that numerical calculations are not on R - at best on Q - this doesn't sound so far-fetched


The results are only absurd if you hold absurd axioms like believing that uncomputable numbers can be computed, or that the real number set is real.


A related fact: all functions are defined on closed sets. You cannot "tell" whether a number is in a set or is a limit point of a set. Since all functions are continuous, they work at limit points too.

As a "practical" consequence: the common design of a random() function returning values in [0, 1) is wrong. Any function you write cannot "tell" whether it got a 1 or not.

These are still very good guidelines even for floating-point code, as long as you, like most everyone else, treat floats as a blackbox abstraction for "real" real numbers.


Well, random() functions that are normally used are defined on the [0, 1) interval of 32-bit or 64-bit IEEE 754 floating point numbers, for which it is very much computable to determine whether they are exactly 1 (there's nothing "real number" about them though, they all belong to a small finite subset of the rations). Of course that isn't really an open interval in the topological sense either.


But that's why it's often a bad idea to test exact equality of floats: the equality test isn't continuous.

In fact, for float computations it's usually even more important to use continuous (ie. error tolerant) functions, since floating-point operations can introduce errors.


Comparing IEEE 754 floating point number is well defined and computable because the domain is discontinuous. It’d be stupid to use anything else…


More precisely, all well-defined computable functions are continuous.

For another exposition of the same (or similar) results, see also Dan Piponi's post from 2008 "What does topology have to do with computability?" at http://blog.sigfpe.com/2008/01/what-does-topology-have-to-do...

Also, as a follow-up, you may be interested in Martin Escardo's 2007 post on the same blog: http://math.andrej.com/2007/09/28/seemingly-impossible-funct...


I'm not a mathematician, but it sounds like what this is saying is that as soon as you allow a number to contain an infinite number of digits, you can get an infinite loop when you try to do a simple comparison. (For example, try to compare pi to an number that's not-quite pi. It might be a little more or a little less, but you can't know this without looking at all the digits, which is impossible.)

As a consequence, there are only two boolean-valued total functions: always return true, or always return false.

I guess that's why we don't use infinite streams of numbers for computation.


You don't need to look at all the digits, but there is no finite stopping point you can choose in advance.

It's similar to the problem of comparing two natural numbers given in least significant bit order.


Given a comparison function, an adversary can construct streams of digits that will make it run forever. This would be true either way. The problem seems to be with allowing algorithmically generated streams as input?

Maybe our domain should be limited to numbers generated by algorithms that are known to terminate? But despite eliminating irrational numbers, this guarantee doesn't seem like enough for practical computing. Even arbitrary precision algorithms require their inputs not only to be computable, but actually computed in advance, showing at least that they fit in memory.


The punchline at the end is worth calling out: Turing Equivalence applies at first-order computations like `Nat -> Nat`, but fails at higher-order computation like `(Nat -> Nat) -> {0, 1}`.


For a very nice into to constructive math, see this[0] link as well as some good HN discussion here[1].

[0]: https://home.sandiego.edu/~shulman/papers/rabbithole.pdf [1]: https://news.ycombinator.com/item?id=18411935


Greg Buchholz in the site's comments linked to Gregory Chaitin's "How real are real numbers?"[1] and asks,

> Isn't it a little bit crazy to talk about computations on real numbers, when most of them are uncomputable/unnameable?

[1] https://arxiv.org/pdf/math/0411418.pdf

> Experimental physicists know how difficult accurate measurements are. No physical quantity has ever been measured with more than 15 or so digits of accuracy. Mathematicians, however, freely fantasize with infinite-precision real numbers. Nevertheless within pure math the notion of a real number is extremely problematic. We’ll compare and contrast two parallel historical episodes:

> 1. the diagonal and probabilistic proofs that reals are uncountable, and

> 2. the diagonal and probabilistic proofs that there are uncomputable reals.

> Both case histories open chasms beneath the feet of mathematicians.


I don't understand the point of arguments about constructible functions on unconstructable reals. I.e. reals with infinite digits and no finite symbolic representation.

For anything actually computable (in finite time), on computable (in finite time) values, you will always get discrete (not continuous) functions on discrete (not continuous) values.


The idea of computable reals go back to at least Turing. The idea is that a real number (or an operation on real numbers) is computable if we can compute the decimal digits, one by one. This way, if the user wants to know it to any desired precision, they just have to wait until the computer has printed that many decimals. You can equivalently treat them as terminating computable functions of type (nat -> bool), which computes the n:th binary decimal.

This is actually a quite constructive notion! At least, it works well with intuinistic mathematics, which is why Andrej Bauer is writing about it.


Ok, that makes sense. Even when restricting numbers to reals with finite symbolic/program definition, comparing two such reals requires an unknown and unbounded number of their digits to be computed. If two symbolic representations define the same number, but it isn't obvious, a complete digit comparison will never end. Got it.

Thank you!


The result presented in TFA is that all computable functions over the real numbers are continuous. To generalize that to 'all functions are continuous', you not only need to believe that all functions should be computable, which sounds reasonable for a constructivist, but also that all numbers should be real, which is not. Back when I was in academia, I remember a talk by a mathematician who thought that we should all be doing analysis with rational numbers rather than real numbers. With such a perspective, the sign function defined over rational numbers (e.g. presented as a pair numerator, denominator) is both discontinuous at 0 and computable.


This reminds me of the coastline paradox: https://en.wikipedia.org/wiki/Coastline_paradox

Specifically, due to the fractal nature of a coastline the length diverges to infinity. The theoretical length at the infinite scale is infinity.


How do you implement algorithms for real numbers if there uncountable many of them? There is always a real number your algorithm cannot read/process.


Algorithms work fine on countable subsets of real numbers, as long as the set you use is discrete at some finite resolution. You only run into trouble if you have no lower bound for separation. It's the same problem even if you have only a countable number of numbers, but you have no lower bound for the smallest positive number or upper bound for the largest number.

Even integers are non computable in finite time, one one of them might be arbitrarily large.


Note that the comments thread below the article addresses some of the natural objections to the novel results exhibited in the post.


In particular,

> the real number is not given by an infinite sequence that is actually written down anywhere, but rather as an algorithm, or a black box, which accepts a number n and outputs the n-th digit. At no point do I manipulate an infinite amount of information, yet I can look at any digit I want. Of course, I cannot look at all digits in a finite time, which is sort of the point of the post.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: