Fast functions for dealing with prime numbers, such as testing whether a number is prime and generating a sequence prime numbers. Additional functions include finding prime factors and Ruth-Aaron pairs, finding next and previous prime numbers in the series, finding or estimating the nth prime, estimating the number of primes less than or equal to an arbitrary number, computing primorials, prime k-tuples (e.g., twin primes), finding the greatest common divisor and smallest (least) common multiple, testing whether two numbers are coprime, and computing Euler's totient function. Most functions are vectorized for speed and convenience.
I've tried to construct prime numbers based on 'inductive definition' (assume we have a set of first n primes, then (n+1)th prime is the least integer such that none of the first n primes is a divisor of it). I've tried to do it in the Fibonacci sequence way, which is:
"Haskell can define data structures in terms of themselves in effect creating infinite data structures". Those prime numbers and Fibonacci sequences mentioned earlier are specific cases of defining data structures in terms of themselves, and Fibonacci sequence works just fine, but these primes doesn't.
Update: You mentioned in a comment that you were thinking of this algorithm imperatively, so you were imagining that Haskell would use a "current" value of tail primes that was still empty in order to evaluate something like [2] ++ [] ++ [3] and then loop. But, of course, Haskell isn't imperative and so doesn't work like this. In Haskell, primes has one, fixed definition that stays the same throughout the execution of the program. A Haskell program can "discover" (or more accurately "compute") the definition gradually, which allows us to define primes in terms of itself in the first place, but it can't change the definition over the course of execution.
So, in looking at this definition, you need to imagine that primes and consequently tail primes have the same value everywhere they appear, even when being used recursively. This is different than a typical recursive function that takes an argument:
Anyway, if we look at this primes definition with the idea that we need primes to be the infinite list of all primes everywhere it appears (and not with a value that changes or "grows" over time), then you can see why this definition won't work. Here, primes is defined as 2 : tail primes ++ [expr] for a complicated expr that does all the real work, but tail primes is supposed to be infinite, so in evaluating this expression you'll never even get to expr, because you'll never exhaust the list tail primes.
isn't the right way to define an infinite list in terms of itself. The problem is that the second element of primes is defined to be the first element of tail primes, which is the second element of primes, so the second element of primes is defined as itself. That will create an infinite loop when Haskell tries to "discover"/"compute" its value. The key to the fibs definition:
To modify your primes definition to work this way, what you probably want to do is generalize your list comprehension from getting the next prime after "2" to get the "next" prime after any current prime p, based on having primes available:
This won't work for two reasons. First, because primes is infinite, this will keep checking divisibility by different k values forever. We need to modify it to check primes k only up to the current prime p:
Second, the check is structured incorrectly. This list comprehension will allow through an x if there's any prime k that doesn't divide it. We need to let through an x only if all primes k don't divide it:
Here, go adds the current prime to the list and then recurses to the next prime, using primeAfter. This works because even though primeAfter p accesses the infinite list primes being generated by the recursive go call, it only uses that list up to the current prime p, so it stops just before trying to access its own value in the list, only using primes generated before the call the primeAfter p.
Your definition, primes = 2:(tail primes) ++ .... says that head primes = 2 and head (tail primes) = head ((tail primes) ++ ....) = head (tail primes). And that's of course problematic, causes infinite recursion.
So it is not fundamentally different from the Fibonacci calculation, although the latter refers only to the previous two elements whereas this one refers to all the previous elements while adding the new one. But just as the Fibonacci stream, this sequence too is defined ultimately in terms of itself: primes = ..... primes .......
The inits makes bar refer to the previously known primes ps explicitly while adding one more to them at each step (expressed by take 1), just like you wanted. concatMap collects all the new one-element segments produced by each invocation of bar.
But why should that be only one prime? Couldn't we safely produce more than one new prime, from the k known previous primes? Must we really test the candidates by all the preceding primes, or can we use the well-known shortcut which you also mention in the question? Can we make it follow the pattern of complete prefix induction, forall(n).(forall( k < floor(sqrt(n)) ).P(k)) => P(n), so that only O(log log n) expansion steps are needed to get to the nth prime?
Could we be producing longer segments on each step from each prefix of the primes sequence (which sequence always stays the same, of course), thus referring not to all the preceding primes for each candidate, but only to a much smaller portion of them?...
Can you fix primes2 so it becomes as fast as primesUpTo, in accessing its nth element? It can follow your original thought, extending the known segment of primes, step by step, as alluded to in the previous section.
Also, do note that no isPrime function is used here at all. Which is the hallmark of the true sieve of Eratosthenes, which does not test for primality, it generates the composites, and gets the primes between the composites, for free.
(The same could be coded with iterate (or unfoldr, etc.). It's a nice exercise, can help clarify what's going on there exactly. When you'll do this, you'll see you'll be re-creating the primes sequence as part of the arguments to the step function being iterated (the current sequence of the first k primes' coprimes, and the next, k+1-th prime, to remove its multiples from that sequence). The scanl versions refer to the original sequence of primes explicitly, taking the primes from it one after another, but it's the same thing.)
The second scanl variant only enumerates the prime's odd multiples, starting each enumeration from the prime's square (so, for e.g. 3 it's [9,15,21,27,...], and for 7 it's [49,63,77,91,...]). It still starts that enumeration for each prime though, not for each prime's square; that's why it has to make special arrangements to stop as soon as it's okay for it to stop, in the primesUpTo function. Which is the key to its efficiency.
The quantity on the left is roughy the probability that, instead of finding $n$ primes in the interval $I_n(a)$, we find exactly $k$. The formula on the right is a Poisson distribution with parameter $n$. It is the naive thing one would expect this limit to converge to, assuming each number $m$ is prime with probability $1/\log(m)$.
These questions on the spacings between primes are expected to be true, but are far from being proved. They are not directly related to RH, but seem to encode other relations among zeros. The conjecture (1) follows from the Hardy-Littlewood prime $k$-tuples conjectures; this was established by Gallagher. More precise versions of Conjecture 2 were considered and formulated by Montgomery and Soundararajan. Here are a few references that address such questions:
Added: It may be helpful to give a brief description of the expected results. First, let us reformulate the problem as asking for an understanding of the number of primes in a random interval $[N,N+h]$ (with $h\le N$ say). For example, question (1) is concerned with the case $h=n\log N$ and the number of times such an interval contains $k$ primes. There are three natural ranges:
(1) $h = \lambda \log N$ for a fixed $\lambda$ (and $N$ chosen randomly). Here one expects the number of primes to be Poisson with parameter $\lambda$ (as in (1) above). This is what Gallagher showed follows from Hardy-Littlewood, and this is consistent with the Cramer model that primes are like random numbers thrown down with mean spacing $\log N$.
It's a mess lol. Is there an easier way, that someone could enlighten me of? I'm half tempted to just saw "Screw it" and burn all my primes into ducats but there's probably some stuff there I'll want.
The distribution of primes over the set of natural numbers is a fascinating subject closely related to topics that range from the fundamental problem of factorization to applications in cryptography. Despite numerous efforts, efficient methods to locate huge primes are still under investigation. Here, we present an alternative approach to identifying prime numbers that is based on the evolution of the linear entanglement entropy. Specifically, we show that a singular behavior in the amplitudes of the Fourier series of this entropy is associated with prime numbers. We also discuss how this intriguing connection between primes and entanglement could be experimentally implemented using existing optical devices, and examine a possible relationship between our results and the zeros of the Riemann zeta function.
Definition 10.63.1. Let $R$ be a ring. Let $M$ be an $R$-module. A prime $\mathfrak p$ of $R$ is associated to $M$ if there exists an element $m \in M$ whose annihilator is $\mathfrak p$. The set of all such primes is denoted $\textAss_ R(M)$ or $\textAss(M)$.
Proof. Choose a filtration as in (3). In Lemma 10.62.5 we have seen that the sets in (1) and (3) are equal. Let $\mathfrak p$ be a minimal element of the set $\ \mathfrak p_ i\ $. Let $i$ be minimal such that $\mathfrak p = \mathfrak p_ i$. Pick $m \in M_ i$, $m \not\in M_i-1$. The annihilator of $m$ is contained in $\mathfrak p_ i = \mathfrak p$ and contains $\mathfrak p_1 \mathfrak p_2 \ldots \mathfrak p_ i$. By our choice of $i$ and $\mathfrak p$ we have $\mathfrak p_ j \not\subset \mathfrak p$ for $j < i$ and hence we have $\mathfrak p_1 \mathfrak p_2 \ldots \mathfrak p_i - 1 \not\subset \mathfrak p_ i$. Pick $f \in \mathfrak p_1 \mathfrak p_2 \ldots \mathfrak p_i - 1$, $f \not\in \mathfrak p$. Then $fm$ has annihilator $\mathfrak p$. In this way we see that $\mathfrak p$ is an associated prime of $M$. By Lemma 10.63.2 we have $\textAss(M) \subset \textSupp(M)$ and hence $\mathfrak p$ is minimal in $\textAss(M)$. Thus the set of primes in (1) is contained in the set of primes of (2). Let $\mathfrak p$ be a minimal element of $\textAss(M)$. Since $\textAss(M) \subset \textSupp(M)$ there is a minimal element $\mathfrak q$ of $\textSupp(M)$ with $\mathfrak q \subset \mathfrak p$. We have just shown that $\mathfrak q \in \textAss(M)$. Hence $\mathfrak q = \mathfrak p$ by minimality of $\mathfrak p$. Thus the set of primes in (2) is contained in the set of primes of (1). $\square$
760c119bf3