AKS Primes
Primality Testing
Python Algorithm
Computational Mathematics
Number Theory

AKS Primes algorithm in Python

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

The AKS primality test is famous because it proved that primality can be decided in deterministic polynomial time. Many Python developers meet it expecting a practical winner. In reality, AKS is mostly educational unless you are studying computational number theory.

Why AKS Is Important

Before AKS, there were very fast primality tests, but the most practical ones either used randomness or depended on extra assumptions. AKS showed that a fully deterministic algorithm could still stay within polynomial time. The key idea is a polynomial congruence: for prime n, certain expansions of (x - a)^n behave in a very specific way modulo n.

You do not need to implement the full proof to understand the workflow. A practical summary looks like this:

  1. Reject n if it is a perfect power.
  2. Find a small integer r where the multiplicative order of n mod r is large enough.
  3. Check for nontrivial common divisors between n and values up to r.
  4. Verify a bounded set of polynomial congruences.
  5. If every test passes, declare n prime.

That sequence is what makes AKS correct, but also slow compared with alternatives such as Miller-Rabin.

A Small Python Building Block

An AKS implementation usually starts with helper functions. The first useful helper is a perfect-power check, because numbers such as 64 = 2^6 can be ruled out immediately.

python
1from math import isqrt
2
3
4def is_perfect_power(n: int) -> bool:
5    if n < 2:
6        return False
7
8    max_exp = n.bit_length()
9    for b in range(2, max_exp + 1):
10        low, high = 2, isqrt(n) + 1
11        while low <= high:
12            mid = (low + high) // 2
13            value = mid ** b
14            if value == n:
15                return True
16            if value < n:
17                low = mid + 1
18            else:
19                high = mid - 1
20    return False
21
22
23for value in [16, 17, 64, 81, 97]:
24    print(value, is_perfect_power(value))

This code is not the whole algorithm, but it demonstrates one of the essential early filters. For composite perfect powers, this is much cheaper than continuing into polynomial checks.

A Simplified AKS Skeleton

The full AKS algorithm needs arithmetic on polynomials reduced modulo both x^r - 1 and n. Writing that from scratch is possible in Python, but it is long and usually distracts from the real lesson. The following version keeps the structure visible while using a simpler polynomial representation based on coefficient lists.

python
1from math import gcd, isqrt, log2
2
3
4def multiplicative_order(n: int, r: int) -> int:
5    if gcd(n, r) != 1:
6        return 0
7
8    value = n % r
9    k = 1
10    while value != 1:
11        value = (value * n) % r
12        k += 1
13    return k
14
15
16def find_small_r(n: int) -> int:
17    limit = int(log2(n) ** 2) + 1
18    r = 2
19    while True:
20        order = multiplicative_order(n, r)
21        if order > limit:
22            return r
23        r += 1
24
25
26def aks_like_primality_test(n: int) -> bool:
27    if n < 2:
28        return False
29    if n in (2, 3):
30        return True
31    if is_perfect_power(n):
32        return False
33
34    r = find_small_r(n)
35
36    for a in range(2, r + 1):
37        d = gcd(a, n)
38        if 1 < d < n:
39            return False
40
41    if n <= r:
42        return True
43
44    # The real AKS step would verify polynomial congruences here.
45    # This placeholder keeps the control flow clear for study.
46    return True
47
48
49for value in [7, 13, 21, 31]:
50    print(value, aks_like_primality_test(value))

Two notes belong with this example. First, this is an educational skeleton, not a production-grade AKS implementation. Second, the placeholder comment matters: without the polynomial congruence step, you do not have the full proof of correctness.

What the Polynomial Step Actually Does

The hardest part of AKS is checking that (x - a)^n behaves like x^n - a after reduction. Instead of expanding huge symbolic expressions directly, implementations work with coefficients modulo n and wrap exponents modulo r. That keeps the polynomial degree bounded.

Conceptually, you can think of multiplication as circular convolution under the relation x^r = 1. Here is a small helper that multiplies two coefficient arrays under that rule.

python
1def poly_mul_mod(poly1, poly2, r, mod_n):
2    result = [0] * r
3    for i, a in enumerate(poly1):
4        for j, b in enumerate(poly2):
5            result[(i + j) % r] = (result[(i + j) % r] + a * b) % mod_n
6    return result
7
8
9print(poly_mul_mod([1, 1], [1, 2], r=4, mod_n=5))

That is the kind of primitive used when building repeated-squaring logic for the congruence test. Once you see it that way, AKS looks less mysterious: it is mainly careful modular arithmetic over a ring of polynomials.

Common Pitfalls

One common mistake is assuming AKS is the best choice for everyday prime checks. In practice, sympy.isprime() or a Miller-Rabin implementation is dramatically faster for typical application code.

Another mistake is calling a partial implementation "AKS" after only checking perfect powers and greatest common divisors. The polynomial congruence stage is not optional. Without it, you have a rough filter, not the full algorithm.

It is also easy to write a multiplicative-order function that loops forever. That happens when gcd(n, r) != 1 and the code never handles the non-coprime case. Always guard that condition before searching for the order.

Finally, Python big integers make experimentation convenient, but they do not make AKS practical for large inputs. If your goal is performance, choose a different algorithm instead of trying to micro-optimize a theoretical one.

Summary

  • AKS matters because it gives a deterministic polynomial-time primality test.
  • The algorithm starts by rejecting perfect powers and searching for a suitable r.
  • The defining step is the polynomial congruence check, not the helper functions around it.
  • A Python implementation is useful for learning, but it is rarely the right production choice.
  • For real applications, faster probabilistic or library-backed tests are usually better.

Course illustration
Course illustration

All Rights Reserved.