3
$\begingroup$

The Möbius function is important in analytic number theory for many reasons.

I'd like to pre-compute a big table of values of the Möbius function to test a few things (sum of Möbius function, i.e. Mertens function, and other similar things, etc.).

Because building a table of Möbius function involves quite long computation (it requires to find the number of prime divisors of each integer):

  1. Is there an online resource that provides a table of $\mu(n)$ for n = 1 ... 10^10 ?

  2. If not, with which programming language would you do this? Maybe would you have open-source code for this?

  • 0
    For most purpose [this code is enough](http://mathoverflow.net/questions/99473/calculating-m%C3%B6bius-function/227408#227408)2017-01-15

5 Answers 5

0

I converted this code into Python. For the following tests, I used Python 64-bit because it uses more than 1 GB of RAM.

mobius(10**6) takes 2.5 seconds with pure Python + numpy.

mobius(10**6) takes 0.7 seconds with Python + numpy + numba (just-in-time compiler).

mobius(10**9) takes 39 seconds with Python + numpy + numba.


import numpy as np
from numba import jit       # comment this line if you don't have numba installed

@jit                        # idem
def mobius(N):
    SQRT = int(np.sqrt(N))
    mu = np.ones(N+1, dtype=np.int32)
    mu[0] = 0

    for i in range(2, SQRT+1):
        if mu[i] == 1:
            for j in range(1, int(N / i)+1):
                mu[i*j] *= -i
            for j in range(1, int(N / i / i)+1):
                mu[i*i*j] = 0

    for i in range(2, N+1):
        if mu[i] == i:
            mu[i] = 1
        elif mu[i] == -i:
            mu[i] = -1
        elif mu[i] < 0:
            mu[i] = 1
        elif mu[i] > 0:
            mu[i] = -1

    return mu

print mobius(10**6)

# Test that shows that it works, see https://oeis.org/A008683
OEISmobius = [0,1,-1,-1,0,-1,1,-1,0,0,1,-1,0,-1,1,1,0,-1,0,-1,0,1,1,-1,0,0,1,0,0,-1,-1,-1,0,1,1,1,0,-1,1,1,0,-1,-1,-1,0,0,1,-1,0,0,0,1,0,-1,0,1,0,1,1,-1,0,-1,1,0,0,1,-1,-1,0,1,-1,-1,0,-1,1,0,0,1,-1]
assert (mobius(78) == OEISmobius).all()

Edit: I also translated this code in Python:

import numpy as np
from numba import jit

@jit
def mobius2(N):
    mu = -np.ones(N+1, dtype=np.int8)
    mu[0] = 0
    mu[1] = 1
    for n in range(2, N+1):
        for m in range(n+n, N, n):
            mu[m] -= mu[n]
    return mu

print mobius2(10**9)   

mobius2(10**9) takes ? seconds with Python + numpy + numba.

  • 0
    `for i in range(2, N): if mu[i] == int8(i) and int8(i) != 0 :` and take a look at the code I linked, replacing `mu[i*j] *= -i` by `mu[i*j] -= mu[i]`2017-01-15
  • 0
    Oh that's right @user1952009. Can you post a full alternate version of the Python code as an answer here?2017-01-15
  • 0
    Because I don't exactly understand what you mentioned. For example in http://mathoverflow.net/a/227408/85239, can you make your final formula (product of sums) more precise? (index in sums, what is your notation $n^0$?, proof for this formula, etc.)2017-01-15
  • 0
    No, why don't you do it ? And if you really want $N > 2^{30}$ you should implement a function for accessing a $dtype=np.int8$ as if it was $dtype=np.int2$. And my code is based on $\sum_{d | n} \mu(d) = 0$ so $\mu(n) = -\sum_{d | n, d < n} \mu(d) $2017-01-15
  • 0
    @user1952009: your last comment to Basj seems not to be in the finest tradition of "sharing your experience" that you took me to task about in your comments on my answer. $\ddot{\smile}$.2017-01-15
2

This may help: Gevorg Hmayakyan wrote a short paper which gives a recursive formula for the $\mu(n)$.

https://ghmath.files.wordpress.com/2010/06/mobius.pdf

It's not for the faint of heart, however. But maybe a faster algorithm could come out of it.

1

A method along the lines of the sieve of Eratosthenes will do what you want quite efficiently. See https://mathoverflow.net/questions/99473/calculating-möbius-function for more details, references and sample code. You will need 64-bit integer arithmetic (or arbitrary magnitude integer arithmetic as provided in Python) to get up to $10^{10}$, but that shouldn't be a problem on modern hardware. You will also need either enough memory to hold the whole table or do something a bit more clever than the sample code in the linked answer.

  • 0
    if you look at [this code](http://mathoverflow.net/questions/99473/calculating-m%C3%B6bius-function/227408#227408), an array of 2bits is enough2017-01-15
  • 0
    You still need $N$ elements in the array to calculate the values up to $\mu(N)$. Even if you pack them tightly $10^{10}$ lots of $2$-bit values is in excess of 4 Gb.2017-01-15
  • 0
    Typo: 2Gb not 4Gb.2017-01-15
  • 0
    I was reacting to "64-bit or arbitrary magnitude integer arithmetic"2017-01-15
  • 0
    But you need to represent and do arithmetic on the indexes into the array. Your code won't get very far if $\mathtt{n}$ is a 2-bit number.2017-01-15
  • 0
    Yes I know, that's why I commented, because what you wrote was unclear. And a 64-bit pointer/index is of course enough (and with my method, 4GB = $\mu(n),n\le 2^{34}-1$ which is quite huge already)2017-01-15
  • 0
    And above $2^{34}$, I'd say a better idea is to compute the Mertens function $M(x)$ for logarithmically spaced $x$2017-01-15
  • 2
    What's unclear? My statement about the example code in the MO link (including yours) is quite clear and correct. And when you say "a better idea", what are you comparing with what?2017-01-15
  • 0
    The Mertens function or something else, but nobody really wants to know $\mu(n)$ for some very high isolated values, whereas $M(x)$ is interesting.2017-01-15
  • 2
    @user1952009 If you want to write a more detailed or informative answer, please do so. If you insist on making your contributions as apparent criticisms of my answer, please defend those criticisms by saying what part of my answer was unclear and which idea in my answer is improved by your mention of the Mertens function. Please also note that the OP apparently wants to have $\mu(n)$ tabulated for many large values of $n$, not just isolated values. If your comments are actually about the question rather than my answer, then please move them to the right place.2017-01-15
  • 0
    ??? Sorry to share my knowledge. I thought this website was made for that. "criticizing" is a big word.2017-01-15
  • 2
    @user1952009: I welcome your intellectual contribution, but if you supply it accompanied by statements like "what you wrote was unclear" or "a better idea is ..." then you are criticising my contribution and it is reasonable for me to ask you to justify your critique.2017-01-15
  • 0
    I'm just sharing my experience. What you wrote is unclear because you didn't mention some codes in the linked questions are better than others (and the OP chose the worst)2017-01-15
  • 2
    @user1952009: Saying my statement that a link on MO contains some example code is unclear because I didn't rank the example code in order of star quality is absurd. If you object to the OP's answer, put your comments under that answer.2017-01-15
  • 0
    Again you have you to stop this attitude, I'm just sharing my knowledge, trying to help.2017-01-16
  • 2
    @user1952009: you have twice stated that something I wrote is unclear and then provided no justification or inadequate justification for that statement when asked to do so. That's not trying to help.2017-01-16
1

B. Goddard makes reference to an interesting paper by Gevorg Hmayakyan on calculating the mobius function. The following source code is in c++ with armadillo and implements one of his equations. The source code leaves a lot to be desired as it involves multiplication of large polynomials etc. I am yet to implement his final equation. At present the code can only handle numbers up to 1000.

void numbertheory::Mobius_Hmayakyan(uword n)
 {
 uword i,j;       //counters
 uword x, y;      // size variables
 ivec Mz(1);      //current Hmayakyan polynomial
 Mz(0)=-1;        // set Hmayakyan polynomial for i=4 Mz=-1
 ivec Mz_1;       //previous Hmayakyan polynomial
 ivec lambda1;     // polynomial ..λ_i-1 = (1+z+z^2+...+z^i-1)
 uvec lambda2;    // polynomial ..λ_i-2 = (1+z+z^2+...+z^i-2)
 uvec phi;      // poynomial phi_3 = λ_1*λ_2...*λ_i-3
 uvec phi_past = {1,1};     // poynomial phi_4 = λ_1*λ_2...*λ_i-4,
 sword mu=0;      //set mobius function for mu(4)=0
 if( n >=1)
    cout << " mu(1) =  1 " <=2)
    cout << " mu(2) = -1" <=3)
    cout << " mu(3) = -1" <=4 )
    cout << " mu(4) =  0" <y)   B.insert_rows(y, x-y);  
  if(x 
  • 0
    I would suggest the following formula for algorithm generation: if $\prod_{i=1}^{n-1}(1-x^i)=\sum_{k=1}^{\frac{n(n-1)}{2}}a_{n,k}x^k$, then $mobius(n)=a_{n, 1}+a_{n, n+1}+a_{n, 2n+1}+a_{n, 3n+1}+... $2017-09-17
  • 1
    Implemented your suggestion and get reliable results. But both approaches suffer from integer overload. My first suggestion aborted at numbers 23. The second based on your suggestion overloaded around 250.2017-09-18
  • 0
    Thank you. I see. Did you take into account that the $a_{n,m}$ can be calculated using $a_{n,m}=a_{n-1,m}-a_{n-1,m-n+1}$ with $a_{2,0}=1; a_{2,1}=-1$?2017-09-19
  • 0
    I am working on your suggestion. On another point, can you suggest a paper discussing the above algorithm for the mobius function.2017-09-21
  • 0
    I am not sure if there is any paper with description of this algorithm. If there will be possible to implement the $a_{n,k}$ enough efficient for according $a_{n,1}$, $a_{n,n+1}$, $a_{n,2n+1}$ then this will bring to a nice algorithm.2017-09-21
1

The second approach of Gevorg Hmayakyan may be of interest [see his comments] as it suggests that the mobius function can be determined from the sign of the coefficients of the pentagonal numbers. Gevorg stated that if $$ ∏^{n−1}_{i=1}(1−x^i)=∑^{n(n−1)/2}_{k=1}a_{n,k}x^k$$ then $$\mu(n)=a_{n,1}+a_{n,n+1}+a_{n,2n+1}+a_{n,3n+1}+...$$ I notice that this function is equivalent to a row of Euler Truncated Product Triangle (see the paper by Alex Mennen at http://www.alex.mennen.org/mahoniantri.pdf). Using Mennens notation we can then state $$\mu(n)=\sum_{k=0}^{\frac{n(n-1)}{2}}P(n-2,kn+1)$$ where $$P(n-2,c)=p(c)+\sum_{k_{1}=0}^{c-n}p(k_{1})+\sum_{k_{2}=0}^{2k_{1}-c}p(k_{2})+\sum_{k_{3}=0}^{2k_{2}-k_{1}}p(k_{3})+\sum_{k_{4}=0}^{2k_{3}-k_{2}}p(k_{4})...$$ and where in accordance to Eulers Pentagonal theorem $p(k)=(-1)^{a}$ if there is some integer $a$ such that $a(3a-1)/2=k$ otherwise it is $0$.

I have generated recursive code based on this function but it highly unsatisfactory. It gives reliable results but the recursion increases quadratically with multiple calls to the same steps and crashes after about n equals 30. One thing of note is that any $\sum_{k=0}^n{p(k)}$ is either $+1,0,-1$. But the function $P(n-2,c)$ is not that simple.

Perhaps someone can take it one step further.