- About
- Notation
- Some basic functions
- Primes and integer factorization
- Arithmetical functions
- Arithmetical function
- Function equality
- Pointwise addition
- Pointwise multiplication
- Divisors
- Additive functions
- Multiplicative functions
- Higher order function for define multiplicative and additive functions
- Some additive functions
- Some multiplicative functions
- Some other arithmetic functions
- Dirichlet convolution
- Congruences
- Primitive roots
This project cover some topics in number theory such as integer factorization, arithmetic functions, congruences, primitive roots.
I wrote this document with Emacs Org Mode. Then I generate markdown
file readme.md with Org Mode export to markdown C-c C-e m m, and
generate pdf file readme.pdf with Org Mode export to pdf C-c C-e l p. Github by default renders readme.md in project root if a project
has such file. Github markdown looks enough good, even math equation
is supported. However for now math equation doesn't render for link
text, pdf file doesn't have any issues with math equations.
I use Emacs babel for clojure to produce real output inside the
document, so it is live documentation and one can open org file in
Emacs. I use org-latex-preview, to preview math equation inside
Emacs, to display all image for all fragments need to use prefix
argument for org-latex-preview function, type C-u C-u C-c C-x C-l
for preview all math equations inside Emacs.
Many applications require integer factorization. Integer factorization
is relatively expensive procedure. Most straightforward way to
factorize integer
The purpose of this library/tool is to provide fast way to play with relatively small numbers(millions) and I made a decision to use least prime divisor table as the best compromise between build factorization table time, required memory for factorization table, integer factorization time. So now factorization is relatively cheap, but it require 4 bytes per number or 4MB for 1000000 numbers.
In this document I load number theory packages as:
(require '[vk.ntheory.basic :as b])
(require '[vk.ntheory.primes :as p])
(require '[vk.ntheory.arithmetic-functions :as f])
(require '[vk.ntheory.congruences :as c])
(require '[vk.ntheory.primitive-roots :as r])
(require '[clojure.math :as math])
So below I will use above aliases.
-
$\mathbf N$ - Natural numbers or positive integers$1,2,3,\dots$ -
$\mathbf C$ - Complex numbers -
$\mathbf Z$ - Integers$\dots -3, -2, -1, 0, 1, 2, 3, \dots$ -
$\mathbf Z/m\mathbf Z$ - Ring of integers modulo$m$ -
$(a,b)$ - the greatest common divisor of$a$ and$b$ -
$[a,b]$ - the least common multiple of$a$ and$b$ -
$a \mid b$ -$a$ divides$b$ -
$a \nmid b$ -$a$ does not divide$b$
This section covers namespace vk.ntheory.basic. It contains some
common functions, which can be used directly or by other namespaces.
One can use vk.ntheory.basic namespace as:
(require '[vk.ntheory.basic :as b])
There are set of check-* functions which can be helpful to validate
user input:
check-intcheck-int-poscheck-int-non-negcheck-int-non-zero
All of above accept one argument, check does argument satisfy to expectation, if does return argument, otherwise throws an exception.
(b/check-int 5)
5
Some check functions accept more than one argument. Those functions throw an exception if expectation failed and returns vector of input arguments otherwise:
-
check-relatively-prime -
check-not-divides -
check-at-least-one-non-zero(b/check-relatively-prime 5 6)
[5 6]
There are also two helper functions check-true and check-predicate
which helps to implement another check-* functions.
Function divides? determine does one number divides another.
(b/divides? 2 8)
true
Function relatively-prime? determine does two numbers relatively prime.
(b/relatively-prime? 2 3)
true
Function product returns cartesian product of n sequences. For instance,
(b/product [(range 1 3) (range 1 5)])
((1 1) (1 2) (1 3) (1 4) (2 1) (2 2) (2 3) (2 4))
Integer
There is a function congruent? which compare does two integers are congruent modulo
(b/congruent? 12 19 7)
true
Similar to addition function + and multiplication function * there
are defined addition modulo m mod-add and multiplication modulo m mod-mul
functions. For instance
(b/mod-add 5 2 4)
1
and
(b/mod-mul 5 2 4)
3
First argument of these functions is a modulo. The fact that modulo is a first argument allow bind modulo in let expression and then use addition and multiplication modulo m without specify a modulo.
(let [mul (partial b/mod-mul 5)
add (partial b/mod-add 5)]
;; ...
(add 1 (mul 2 4)))
4
There is another helpful function modulo m - exponentiation. It is
implementation of a fast exponentiation algorithm described in
D.Knuth, The Art of Computer Programming, Volume II. and in book
Structure and Interpretation of Computer Programs (SICP) of Harold
Abelson and Gerald Jay Sussman. For instance,
(b/mod-pow 997 101 900)
701
Clojure has built-in clojure.math/pow function, but it return
java.lang.Double. The library provide integer analog. Also the
implementation share fast exponentiation algorithm with mod-pow
function.
(b/pow 2 3)
8
Order function
(b/order 2 24)
3
The sign function defined as follows:
(mapv b/sign [(- 5) 10 0])
[-1 1 0]
The greatest common divisor of two integers
(b/gcd 12 18)
6
The greatest common divisors of
(b/gcd-extended 12 18)
[6 [-1 1]]
The least common multiple of two non zero integers
(b/lcm 12 18)
36
This section cover namespace vk.ntheory.primes. It primary designed
for integer factorization and get list of primes. One can use
vk.ntheory.primes namespace as:
(require '[vk.ntheory.primes :as p])
Addition to vk.nthery.basic namespace, namespace vk.ntheory.primes
provides additional set of check-* functions:
check-int-pos-maxcheck-int-non-neg-maxcheck-int-non-zero-max
It is similar to vk.ntheory.basic check functions, but additionally check
that given number does not exceed max-int constant. And there are some
more check functions:
check-primecheck-odd-prime
This library is designed to work with relatively small integers. Library
keep in cache least prime divisor table for fast integer
factorization. Least prime divisor of an positive integer is least
divisor, but not 1. Cache grows automatically. The strategy of
growing is extends cache to the least power of 10 more than required
number. For instance, if client asked to factorize number 18, cache
grows to 100, if client asked to factorize number 343, cache grows
to 1000. List of primes also cached and recalculated together with
least prime divisor table. Recalculation is not incremental, but every
recalculation of least prime divisor table make a table which is in
10 times more than previous, and time for previous calculation is
10 times less than for new one. So we can say that recalculation
spent almost all time for recalculate latest least prime divisor
table.
Internally, least prime divisor table is java array of int, so to store
least prime divisor table for first 1 000 000 number approximately 4M
memory is required, 4 bytes per number.
There is a limit for max size of least prime divisor table. It is value of
max-int:
p/max-int
10000000
Cache can be reset:
(p/cache-reset!)
{:least-divisor-table , :primes , :upper 0}
Least prime divisor table is implementation details, but one can see it:
;; load first 10 numbers into cache
(p/int->factors-map 5)
(deref p/cache)
{:least-divisor-table [0, 1, 2, 3, 2, 5, 2, 7, 2, 3, 2],
:primes (2 3 5 7),
:upper 10}
For number n least prime divisor table contains least prime divisor
of number n at index n. For instance, least prime divisor of
number 6 is 2. If number n > 1 is a prime, least prime divisor
is n and conversely. So at index 7 least prime divisor table
contains 7. Index zero is not used, index 1 is a special case and
value for index 1 is 1.
primes function returns prime numbers which not exceeds given n.
(p/primes 30)
(2 3 5 7 11 13 17 19 23 29)
Integer
$p > 1$ -
$p$ has just two divisors, namely$1$ and$p$ .
There is prime? predicate:
(p/prime? 7)
true
Integer
$n > 1$ -
$n$ has at least one divisor except$1$ and$n$
There is composite? predicate:
(p/composite? 12)
true
Integer
(p/unit? 1)
true
So all natural numbers can be divided into 3 categories: prime, composite and unit.
Every integer more than
or we can write it in more compact form:
or even write as:
For example,
There are some functions to factorize integers. Each of them accept
natural number as an argument and returns factorized value. It have
slightly different output, which may be more appropriate to different
use cases. For each factorize function there is also inverse function,
which accept factorized value and convert it back to integer. It is
convenient to consider empty product as
1-st factorization representation is ordered sequence of primes:
(p/int->factors 360)
(2 2 2 3 3 5)
And reverse function is:
(p/factors->int [2 2 2 3 3 5])
360
2-nd factorization representation is ordered sequence of primes grouped into partitions by a prime:
(p/int->factors-partitions 360)
((2 2 2) (3 3) (5))
And reverse function is:
(p/factors-partitions->int [[2 2 2] [3 3] [5]])
360
3-rd factorization representation is ordered sequence of pairs [p k], where p is a prime and k is a power of prime:
(p/int->factors-count 360)
([2 3] [3 2] [5 1])
And reverse function is:
(p/factors-count->int [[2 3] [3 2] [5 1]])
360
4-th factorization representation is very similar to 3-rd, but it is a map instead of sequence of pairs.
(p/int->factors-map 360)
{2 3, 3 2, 5 1}
Reverse function is the same as for 3-rd representation:
(p/factors-count->int {2 3, 3 2, 5 1})
360
5-th factorization representation is sequence of coprime integers,
that's it every pair of factors from the sequence are relatively
prime. If we take 4-th factorization and raise every prime to
appropriate power we get 5-th factorization. For instance,
(p/int->coprime-factors 360)
(8 9 5)
Reverse function is the same as for 1-st representation
(p/factors->int [8 9 5])
360
Implementation of factorization functions use least prime divisor
table. Actually least prime divisor table is a kind of linked list, to
get ordered list of all divisors of an integer n, need to get least
prime divisor at index n, let it be p, p is a first element of
the list, then divide n on p, the index of quotient n/p is next
element of "linked list".
This section cover namespace vk.ntheory.primes. It contains some
well known arithmetical functions and also functions which allow build
new arithmetical functions.
(require '[vk.ntheory.arithmetic-functions :as f])
Arithmetical function is an any function which accept natural number
and return complex number
Two arithmetical function f= which compare two functions
on some sequence(sample) of natual numbers. Function f= accept two
functions and optionally sequence of natural numbers. There is a
default for sequence of natural numbers, it is a variable
default-natural-sample, which is currently range(1,100).
(take 10 f/default-natural-sample)
(1 2 3 4 5 6 7 8 9 10)
If we like identify does two function f and g equals on some
sequence of natural number we can for example do next:
;; Let we have some f and g
(def f identity)
(def g (constantly 1))
;; Then we able to check does those functions are equals
(f/equal f g) ;; true
(f/equal f g (range 1 1000)) ;; true
(f/equal f g (filter even? (range 1 100))) ;; true
For two functions
In Clojure function pointwise-add returns pointwise addition:
(let [f #(* % %)
g #(* 2 %)]
((f/pointwise-add f g) 3))
15
For two functions
In clojure function pointwise-mul returns pointwise multiplication:
(let [f #(* % %)
g #(* 2 %)]
((f/pointwise-mul f g) 3))
54
Some arithmetic functions and Dirichlet convolutions need to iterate
over positive divisors on an integer. For get list of all positive
divisors of number n there is divisor function. List of divisors
is unordered.
(f/divisors 30)
(1 5 3 15 2 10 6 30)
Additive function is a function for which
if
To define an additive function it is enough to define how to
calculate a function on power of primes.
If
Multiplicative function is a function not equal to zero for all n for which
if
To define multiplicative function it is enough to define how to
calculate a function on power of primes. If
As we have seen, to define either multiplicative or additive function
it is enough define function on power of a prime. There is helper
function reduce-on-prime-count which provide a way to define a
function on power of a prime. The first parameter of
reduce-on-prime-count is reduce function which usually * for
multiplicative function and usually + for additive function, but
custom reduce function also acceptable.
For instance, we can define function which calculate number of
divisors of integer n. If n can be calculated by formula:
With helper function it can be defined as
(def my-divisors-count
(f/reduce-on-prime-count * (fn [p k] (inc k))))
(my-divisors-count 6)
4
Of course there is predefined function divisors-count, but it
is an example how to define custom function.
Count of distinct primes is a number of distinct primes which
divides given
(f/primes-count-distinct (* 2 2 3))
2
Total count of primes is a number of primes and power of primes
which divides
(f/primes-count-total (* 2 2 3))
3
Mobius function
For example,
(f/mobius 6)
1
Euler totient function
For example, count of numbers relative prime to
(f/totient 6)
2
Unit or identity function defined as follows:
(f/unit 6)
0
The name unit was chosen to make it different from
clojure.core/identity function.
Constant one function
(f/one 6)
1
Function divisors count is a number of positive divisors which divides
given number
Function
(f/divisors-count 6)
4
Function divisors sum is sum of positive divisors which divides given
number
Function
(f/divisors-sum 6)
12
Function divisors square sum defined as follows:
For instance,
(f/divisors-square-sum 6)
50
In general
If
and if
There is higher order function divisors-sum-x which
accept x and return appropriate function.
For example we can define divisors cube sum as follows:
(def my-divisors-cube-sum (f/divisors-sum-x 3))
Liouville function
(f/liouville (* 2 3))
1
Liouville function is completely multiplicative.
Mangoldt function
For example
(f/mangoldt 2)
0.6931471805599453
If
(f/chebyshev-theta 2)
0.6931471805599453
If
(f/chebyshev-psi 2)
0.6931471805599453
For two arithmetic functions
Dirichlet convolution is associative:
Commutative:
Has identify:
For every
In clojure, function dirichlet-mul calculate Dirichlet convolution:
(f/dirichlet-mul f/one f/one)
Function dirichlet-inverse calculate Dirichlet inverse:
(f/dirichlet-inverse f/one)
Dirichlet convolution is associative so clojure function dirichlet-multiplication support
more than two function as an argument.
(f/dirichlet-mul f/mobius f/one f/mobius f/one)
#function[vk.ntheory.arithmetic-functions/dirichlet-mul/fn--6199]
Functions
(f/equal (f/dirichlet-inverse f/one) f/mobius)
true
and conversely
(f/equal (f/dirichlet-inverse f/mobius) f/one)
true
Function dirichlet-inverse defined as recursive function, it may execute
slow. But inverse of completely multiplicative function
(f/equal
(f/dirichlet-mul
(f/pointwise-mul identity f/mobius)
identity
)
f/unit)
true
This section cover namespaces vk.ntheory.congruence. It contains
functions for solve any congruence with brute force approach and also
contains solutions for specific congruences such as linear congruence
and system of linear congruences.
(require '[vk.ntheory.congruences :as c])
If we have a congruence
we can solve it by try all solve function for this. It accept two aruments, first argument is a
some function of one argument and second arument is a modulo. Let's
for example solve congruence
(let [f (fn [x] (dec (* x x)))]
(c/solve f 8)
)
(1 3 5 7)
Let consider linear congruence
There is function solve-linear for solve linear congruence. It accepts
3 arguments a, b and m. Let's solve congruence
(c/solve-linear 6 3 15)
#{3 8 13}
Let consider system of linear congruences:
There is a function solve-remaindes for solve such system. It accepts
a sequence of pairs
Let's solve system:
(c/solve-remainders [[2 7][5 9][11 15]])
[86 315]
So the answer is
When we have system of linear conguences:
and any pair of moduli relatively prime, i.e. solve-remainder function, but there is
another function solve-coprime-remainders. It accepts a sequence of
pairs
Let's solve system:
(c/solve-remainders [[6 17][4 11][-3 8]])
[125 1496]
So the answer is
This section cover namespace vk.ntheory.primitive-roots.
It contains functions for test modulo for primitive roots, find primitive roots. If modulo has a primitive root there are functions for find index, test for n-th power residue, solve n-th power residue congruence, get all n-th power residues. Also there is a function for find reduced residues by any modulo.
(require '[vk.ntheory.primitive-roots :as r])
Function reduced-residues return reduced residues modulo m.
(r/reduced-residues 12)
(7 11 1 5)
Order
(r/order 2 11)
1
If order find-primitive-root.
(r/find-primitive-root 11)
2
There is a predicate primitive-root? to check does given number
(r/primitive-root? 2 11)
true
To find all primitive roots there is function primitive-roots.
(r/primitive-roots 11)
(7 6 2 8)
If m has a primitive root
Number
There is clojure function index [m g a] to calculate index.
(r/index 11 2 5)
4
Often it doesn't matter which primitive root used as base. There is
another arity of function index [m a], where find-primitive-root function, which is
(r/index 11 5)
4
If
To check does given number power residue there is a function power-residue?.
For instance
(r/power-residue? 11 2 4)
true
If need to get solutions of equation
(r/solve-power-residue 11 2 4)
#{2 9}
If need to get all n-th power residues modulo power-residues. For instance for get all
(r/power-residues 11 2)
(1 4 5 9 3)