> {
static constexpr ModularInt add(const ModularInt
& a, const ModularInt
& b) noexcept {
return a + b;
}
static constexpr ModularInt
subtract(const ModularInt
& a, const ModularInt
& b) noexcept {
return a - b;
}
static constexpr ModularInt
multiply(const ModularInt
& a, const ModularInt
& b) noexcept {
return a * b;
}
static ModularInt
divide(const ModularInt
& a, const ModularInt
& b) {
return a / b;
}
static constexpr ModularInt
negate(const ModularInt
& a) noexcept {
return -a;
}
static constexpr ModularInt
zero() noexcept {
return ModularInt
(0);
}
static constexpr ModularInt
one() noexcept {
return ModularInt
(1);
}
static constexpr bool equals(const ModularInt
& a, const ModularInt
& b) noexcept {
return a == b;
}
static constexpr bool less_than(const ModularInt
& a, const ModularInt
& b) noexcept {
return a < b;
}
};
} // namespace concepts
// MKL support
#if SANGI_HAS_MKL
namespace detail {
namespace matrix_mkl {
// MKL operation interface for ModularInt (MKL has no direct support, so a custom implementation)
template
class ModularIntMklOperations {
public:
// Vector addition: y = a*x + y
static void axpy(int n, ModularInt alpha, const ModularInt
* x, int incx,
ModularInt
* y, int incy) {
for (int i = 0; i < n; ++i) {
y[i * incy] += alpha * x[i * incx];
}
}
// Vector dot product: result = x . y
static ModularInt
dot(int n, const ModularInt
* x, int incx,
const ModularInt
* y, int incy) {
ModularInt
result(0);
for (int i = 0; i < n; ++i) {
result += x[i * incx] * y[i * incy];
}
return result;
}
// Matrix multiplication: C = alpha*A*B + beta*C
static void gemm(int layout, int transA, int transB, int m, int n, int k,
ModularInt
alpha, const ModularInt
* A, int lda,
const ModularInt
* B, int ldb, ModularInt
beta,
ModularInt
* C, int ldc) {
// Apply beta to C
if (beta != ModularInt
(1)) {
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
C[i*ldc + j] = beta * C[i*ldc + j];
}
}
}
// Only row-major format is supported (simplified implementation)
if (layout != CblasRowMajor || transA != CblasNoTrans || transB != CblasNoTrans) {
throw MathError("Unsupported matrix layout or transposition for ModularInt");
}
// Compute A*B and add to C
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
ModularInt
sum(0);
for (int l = 0; l < k; ++l) {
sum += A[i*lda + l] * B[l*ldb + j];
}
C[i*ldc + j] += alpha * sum;
}
}
}
// Implement additional MKL-compatible functions as needed
};
} // namespace matrix_mkl
} // namespace detail
#endif // SANGI_HAS_MKL
// Number-theoretic functions specific to ModularInt
// extended_gcd, chinese_remainder_theorem, and CRT class are defined in CRT.hpp
/**
* @brief Fast modular exponentiation
* @tparam P Modulus
* @param base Base
* @param exponent Exponent
* @return Computation result
*/
template
constexpr ModularInt mod_pow(const ModularInt
& base, int64_t exponent) {
return base.pow(exponent);
}
/**
* @brief Compute a primitive root
* @tparam P Prime modulus
* @return A primitive root of P, or nullopt if none is found
*/
template
std::optional> find_primitive_root() {
if (P <= 1) {
return std::nullopt;
}
// Prime factorization of P-1
int64_t phi = P - 1;
std::vector prime_factors;
// Prime factorization (naive algorithm)
int64_t n = phi;
for (int64_t i = 2; i * i <= n; ++i) {
if (n % i == 0) {
prime_factors.push_back(i);
while (n % i == 0) {
n /= i;
}
}
}
if (n > 1) {
prime_factors.push_back(n);
}
// Search for primitive-root candidates
for (int g = 2; g < P; ++g) {
bool is_primitive = true;
ModularInt candidate(g);
for (int64_t prime : prime_factors) {
if (candidate.pow(phi / prime) == ModularInt
(1)) {
is_primitive = false;
break;
}
}
if (is_primitive) {
return ModularInt
(g);
}
}
return std::nullopt;
}
/**
* @brief Fast modular exponentiation (non-member function)
* @tparam P Modulus
* @param base Base
* @param exponent Exponent
* @return Computation result
*/
template
constexpr ModularInt pow_mod(int64_t base, int64_t exponent) {
return ModularInt
(base).pow(exponent);
}
/**
* @brief Modular inverse (using Fermat's little theorem)
* @tparam P Prime modulus
* @param a The value whose inverse is sought
* @return Modular inverse of a
*/
template
constexpr ModularInt mod_inverse(int64_t a) {
return ModularInt
(a).inverse();
}
/**
* @brief Modular congruence solver
* @tparam P Modulus
* @param a Coefficient
* @param b Constant term
* @return Array of solutions x to ax = b (mod P)
*/
template
std::vector> solve_congruence(int64_t a, int64_t b) {
a = (a % P + P) % P;
b = (b % P + P) % P;
std::vector> solutions;
// Compute the GCD of a and P
int64_t g = std::gcd(a, static_cast(P));
if (b % g != 0) {
// No solution
return solutions;
}
// a' x = b' (mod P'), where a' = a/g, b' = b/g, P' = P/g
a /= g;
b /= g;
int64_t mod_prime = P / g;
// Compute the inverse of a'
ModularInt a_inv = ModularInt
(a).inverse();
// Base solution x_0 = a^(-1) * b (mod P/g)
ModularInt
x0 = a_inv * ModularInt
(b);
// Generate all solutions: x_k = x_0 + k * (P/g) for k = 0, 1, ..., g-1
for (int64_t k = 0; k < g; ++k) {
solutions.push_back(x0 + ModularInt
(k * mod_prime));
}
return solutions;
}
} // namespace sangi
#endif // SANGI_MODULAR_INT_TRAITS_HPP