Skip to content

Commit 89433b1

Browse files
committed
Move number theory stuff to separate folder
1 parent b79d09a commit 89433b1

22 files changed

+149
-59
lines changed

cp-algo/linalg/vector.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef CP_ALGO_LINALG_VECTOR_HPP
22
#define CP_ALGO_LINALG_VECTOR_HPP
33
#include "../random/rng.hpp"
4-
#include "../math/modint.hpp"
4+
#include "../number_theory/modint.hpp"
55
#include <functional>
66
#include <algorithm>
77
#include <valarray>

cp-algo/math/fft.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef CP_ALGO_MATH_FFT_HPP
22
#define CP_ALGO_MATH_FFT_HPP
33
#include "common.hpp"
4-
#include "modint.hpp"
4+
#include "cp-algo/number_theory/modint.hpp"
55
#include <algorithm>
66
#include <complex>
77
#include <cassert>

cp-algo/math/number_theory.hpp

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,13 @@
11
#ifndef CP_ALGO_MATH_NUMBER_THEORY_HPP
22
#define CP_ALGO_MATH_NUMBER_THEORY_HPP
3-
#include "../random/rng.hpp"
3+
#include "cp-algo/random/rng.hpp"
4+
#include "number_theory/modint.hpp"
45
#include "affine.hpp"
5-
#include "factorize.hpp"
66
#include <algorithm>
77
#include <optional>
88
#include <vector>
99
#include <bit>
1010
namespace cp_algo::math {
11-
int64_t euler_phi(int64_t m) {
12-
auto primes = factorize(m);
13-
std::ranges::sort(primes);
14-
auto [from, to] = std::ranges::unique(primes);
15-
primes.erase(from, to);
16-
int64_t ans = m;
17-
for(auto it: primes) {
18-
ans -= ans / it;
19-
}
20-
return ans;
21-
}
22-
template<modint_type base>
23-
int64_t period(base x) {
24-
auto ans = euler_phi(base::mod());
25-
base x0 = bpow(x, ans);
26-
for(auto t: factorize(ans)) {
27-
while(ans % t == 0 && x0 * bpow(x, ans / t) == x0) {
28-
ans /= t;
29-
}
30-
}
31-
return ans;
32-
}
3311
// Find min non-negative x s.t. a*b^x = c (mod m)
3412
std::optional<uint64_t> discrete_log(int64_t b, int64_t c, uint64_t m, int64_t a = 1) {
3513
if(std::abs(a - c) % m == 0) {
@@ -89,15 +67,5 @@ namespace cp_algo::math {
8967
}
9068
}
9169
}
92-
int64_t primitive_root(int64_t p) {
93-
using base = dynamic_modint;
94-
return base::with_mod(p, [p](){
95-
base t = 1;
96-
while(period(t) != p - 1) {
97-
t = random::rng();
98-
}
99-
return t.getr();
100-
});
101-
}
10270
}
10371
#endif // CP_ALGO_MATH_NUMBER_THEORY_HPP

cp-algo/math/poly.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include "poly/impl/base.hpp"
55
#include "poly/impl/div.hpp"
66
#include "combinatorics.hpp"
7-
#include "number_theory.hpp"
7+
#include "cp-algo/number_theory/discrete_sqrt.hpp"
88
#include "fft.hpp"
99
#include <functional>
1010
#include <algorithm>

cp-algo/number_theory.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#ifndef CP_ALGO_NUMBER_THEORY_HPP
2+
#define CP_ALGO_NUMBER_THEORY_HPP
3+
#include "number_theory/discrete_log.hpp"
4+
#include "number_theory/discrete_sqrt.hpp"
5+
#include "number_theory/euler.hpp"
6+
#include "number_theory/factorize.hpp"
7+
#include "number_theory/modint.hpp"
8+
#include "number_theory/primality.hpp"
9+
#include "number_theory/two_squares.hpp"
10+
#endif // CP_ALGO_NUMBER_THEORY_HPP
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#ifndef CP_ALGO_NUMBER_THEORY_DISCRETE_LOG_HPP
2+
#define CP_ALGO_NUMBER_THEORY_DISCRETE_LOG_HPP
3+
#include "euler.hpp"
4+
namespace cp_algo::math {
5+
// Find min non-negative x s.t. a*b^x = c (mod m)
6+
std::optional<uint64_t> discrete_log(int64_t b, int64_t c, uint64_t m, int64_t a = 1) {
7+
if(std::abs(a - c) % m == 0) {
8+
return 0;
9+
}
10+
if(std::gcd(a, m) != std::gcd(a * b, m)) {
11+
auto res = discrete_log(b, c, m, a * b % m);
12+
return res ? std::optional(*res + 1) : res;
13+
}
14+
// a * b^x is periodic here
15+
using base = dynamic_modint;
16+
return base::with_mod(m, [&]() -> std::optional<uint64_t> {
17+
size_t sqrtmod = std::max<size_t>(1, std::sqrt(m) / 2);
18+
std::unordered_map<int64_t, int> small;
19+
base cur = a;
20+
for(size_t i = 0; i < sqrtmod; i++) {
21+
small[cur.getr()] = i;
22+
cur *= b;
23+
}
24+
base step = bpow(base(b), sqrtmod);
25+
cur = 1;
26+
for(size_t k = 0; k < m; k += sqrtmod) {
27+
auto it = small.find((base(c) * cur).getr());
28+
if(it != end(small)) {
29+
auto cand = base::with_mod(period(base(b)), [&](){
30+
return base(it->second - k);
31+
}).getr();
32+
if(base(a) * bpow(base(b), cand) == base(c)) {
33+
return cand;
34+
} else {
35+
return std::nullopt;
36+
}
37+
}
38+
cur *= step;
39+
}
40+
return std::nullopt;
41+
});
42+
}
43+
}
44+
#endif // CP_ALGO_NUMBER_THEORY_DISCRETE_LOG_HPP
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#ifndef CP_ALGO_NUMBER_THEORY_DISCRETE_SQRT_HPP
2+
#define CP_ALGO_NUMBER_THEORY_DISCRETE_SQRT_HPP
3+
#include "modint.hpp"
4+
#include "cp-algo/random/rng.hpp"
5+
#include "cp-algo/math/affine.hpp"
6+
namespace cp_algo::math {
7+
// https://en.wikipedia.org/wiki/Berlekamp-Rabin_algorithm
8+
template<modint_type base>
9+
std::optional<base> sqrt(base b) {
10+
if(b == base(0)) {
11+
return base(0);
12+
} else if(bpow(b, (b.mod() - 1) / 2) != base(1)) {
13+
return std::nullopt;
14+
} else {
15+
while(true) {
16+
base z = random::rng();
17+
if(z * z == b) {
18+
return z;
19+
}
20+
lin<base> x(1, z, b); // x + z (mod x^2 - b)
21+
x = bpow(x, (b.mod() - 1) / 2, lin<base>(0, 1, b));
22+
if(x.a != base(0)) {
23+
return x.a.inv();
24+
}
25+
}
26+
}
27+
}
28+
}
29+
#endif // CP_ALGO_NUMBER_THEORY_SQRT_HPP

cp-algo/number_theory/euler.hpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#ifndef CP_ALGO_NUMBER_THEORY_EULER_HPP
2+
#define CP_ALGO_NUMBER_THEORY_EULER_HPP
3+
#include "factorize.hpp"
4+
namespace cp_algo::math {
5+
int64_t euler_phi(int64_t m) {
6+
auto primes = factorize(m);
7+
std::ranges::sort(primes);
8+
auto [from, to] = std::ranges::unique(primes);
9+
primes.erase(from, to);
10+
int64_t ans = m;
11+
for(auto it: primes) {
12+
ans -= ans / it;
13+
}
14+
return ans;
15+
}
16+
template<modint_type base>
17+
int64_t period(base x) {
18+
auto ans = euler_phi(base::mod());
19+
base x0 = bpow(x, ans);
20+
for(auto t: factorize(ans)) {
21+
while(ans % t == 0 && x0 * bpow(x, ans / t) == x0) {
22+
ans /= t;
23+
}
24+
}
25+
return ans;
26+
}
27+
int64_t primitive_root(int64_t p) {
28+
using base = dynamic_modint;
29+
return base::with_mod(p, [p](){
30+
base t = 1;
31+
while(period(t) != p - 1) {
32+
t = random::rng();
33+
}
34+
return t.getr();
35+
});
36+
}
37+
}
38+
#endif // CP_ALGO_NUMBER_THEORY_EULER_HPP

cp-algo/math/factorize.hpp renamed to cp-algo/number_theory/factorize.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef CP_ALGO_MATH_FACTORIZE_HPP
22
#define CP_ALGO_MATH_FACTORIZE_HPP
33
#include "primality.hpp"
4-
#include "../random/rng.hpp"
4+
#include "cp-algo/random/rng.hpp"
55
namespace cp_algo::math {
66
// https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
77
void factorize(uint64_t m, std::vector<int64_t> &res) {

cp-algo/math/modint.hpp renamed to cp-algo/number_theory/modint.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
#ifndef CP_ALGO_MATH_MODINT_HPP
2-
#define CP_ALGO_MATH_MODINT_HPP
3-
#include "common.hpp"
1+
#ifndef CP_ALGO_NUMBER_THEORY_MODINT_HPP
2+
#define CP_ALGO_NUMBER_THEORY_MODINT_HPP
3+
#include "cp-algo/math/common.hpp"
44
#include <iostream>
55
namespace cp_algo::math {
66
template<typename modint>

0 commit comments

Comments
 (0)