2016-11-19 20:55:11 +01:00
|
|
|
#ifndef KNOTKIT_ALGEBRA_ZP_H
|
|
|
|
#define KNOTKIT_ALGEBRA_ZP_H
|
2016-11-19 21:01:10 +01:00
|
|
|
#include <algebra/Z.h>
|
2016-11-19 20:55:11 +01:00
|
|
|
#include <iostream>
|
|
|
|
#include <tuple>
|
|
|
|
#include <cassert>
|
2011-12-14 19:07:53 +01:00
|
|
|
|
|
|
|
template<unsigned p>
|
|
|
|
class Zp
|
|
|
|
{
|
|
|
|
public:
|
2016-11-19 20:55:11 +01:00
|
|
|
using linear_combination = ::linear_combination<Zp<p>>;
|
|
|
|
using linear_combination_const_iter = ::linear_combination_const_iter<Zp<p>>;
|
2011-12-14 19:07:53 +01:00
|
|
|
|
|
|
|
private:
|
|
|
|
unsigned v;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Zp () : v(0) { }
|
|
|
|
Zp (unsigned init) : v(init % p) { }
|
|
|
|
Zp (int init)
|
|
|
|
{
|
|
|
|
int i = init % (int)p;
|
|
|
|
if (i < 0)
|
|
|
|
i += p;
|
|
|
|
assert (i >= 0 && i < (int)p);
|
|
|
|
v = i;
|
|
|
|
}
|
|
|
|
|
2016-11-19 20:55:11 +01:00
|
|
|
Zp (const Zp& x) : v(x.v) { }
|
|
|
|
Zp (copy, const Zp& x) : v(x.v) {}
|
|
|
|
Zp (Zp&& x) : v(std::move(x.v)) {
|
|
|
|
x.v = 0;
|
|
|
|
}
|
2016-11-19 21:01:10 +01:00
|
|
|
Zp (const Z& z) : v((z % p).get_ui()) {}
|
2011-12-14 19:07:53 +01:00
|
|
|
~Zp () { }
|
|
|
|
|
2016-11-19 20:55:11 +01:00
|
|
|
Zp& operator = (const Zp& x) { v = x.v; return *this; }
|
|
|
|
Zp& operator = (Zp&& x) { v = x.v; x.v = 0; return *this; }
|
|
|
|
Zp& operator = (int x)
|
2011-12-14 19:07:53 +01:00
|
|
|
{
|
|
|
|
return operator = (Zp (x));
|
|
|
|
}
|
|
|
|
|
2016-11-19 20:55:11 +01:00
|
|
|
bool operator == (const Zp& x) const { return v == x.v; }
|
|
|
|
bool operator != (const Zp& x) const { return !operator == (x); }
|
2011-12-14 19:07:53 +01:00
|
|
|
|
|
|
|
bool operator == (int x) const { return operator == (Zp (x)); }
|
|
|
|
bool operator != (int x) const { return !operator == (x); }
|
|
|
|
|
2016-11-19 20:55:11 +01:00
|
|
|
bool operator < (const Zp& x) const { return v < x.v; }
|
2011-12-14 19:07:53 +01:00
|
|
|
|
|
|
|
bool is_unit () const
|
|
|
|
{
|
|
|
|
return v != 0;
|
|
|
|
}
|
|
|
|
|
2016-11-19 20:55:11 +01:00
|
|
|
Zp operator + (const Zp& x) const { return Zp (v + x.v); }
|
|
|
|
Zp operator - (const Zp& x) const { return Zp ((int)v - (int)x.v); }
|
2011-12-14 19:07:53 +01:00
|
|
|
Zp operator - () const { return Zp (- (int)v); }
|
|
|
|
|
2016-11-19 20:55:11 +01:00
|
|
|
Zp operator * (const Zp& x) const { return Zp (v * x.v); }
|
2011-12-14 19:07:53 +01:00
|
|
|
|
2016-11-19 20:55:11 +01:00
|
|
|
Zp operator / (const Zp& x) const
|
2011-12-14 19:07:53 +01:00
|
|
|
{
|
|
|
|
return operator * (x.recip ());
|
|
|
|
}
|
|
|
|
|
|
|
|
Zp recip () const
|
|
|
|
{
|
2016-11-19 20:55:11 +01:00
|
|
|
std::tuple<unsigned, int, int> t = unsigned_extended_gcd (v, p);
|
|
|
|
assert (std::get<0> (t) == 1);
|
|
|
|
assert ((int)std::get<0> (t) == std::get<1> (t)*(int)v + std::get<2> (t)*(int)p);
|
2011-12-14 19:07:53 +01:00
|
|
|
|
2016-11-19 20:55:11 +01:00
|
|
|
return Zp (std::get<1> (t));
|
2011-12-14 19:07:53 +01:00
|
|
|
}
|
|
|
|
|
2016-11-19 20:55:11 +01:00
|
|
|
Zp& operator += (const Zp& x)
|
2011-12-14 19:07:53 +01:00
|
|
|
{
|
|
|
|
v = (v + x.v) % p;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2016-11-19 20:55:11 +01:00
|
|
|
Zp& operator -= (const Zp& x) { return operator = (Zp ((int)v - (int)x.v)); }
|
2011-12-14 19:07:53 +01:00
|
|
|
|
2016-11-19 20:55:11 +01:00
|
|
|
Zp& operator *= (const Zp& x)
|
2011-12-14 19:07:53 +01:00
|
|
|
{
|
|
|
|
v = (v * x.v) % p;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2016-11-19 20:55:11 +01:00
|
|
|
Zp& operator /= (const Zp& x)
|
2011-12-14 19:07:53 +01:00
|
|
|
{
|
|
|
|
return operator *= (x.recip ());
|
|
|
|
}
|
|
|
|
|
|
|
|
// d | n, d.divides (n)
|
2016-11-19 20:55:11 +01:00
|
|
|
bool divides (const Zp& n) const
|
2011-12-14 19:07:53 +01:00
|
|
|
{
|
|
|
|
return v || !n.v;
|
|
|
|
}
|
|
|
|
|
2016-11-19 20:55:11 +01:00
|
|
|
bool operator | (const Zp& n) const { return divides (n); }
|
2011-12-14 19:07:53 +01:00
|
|
|
|
2016-11-19 20:55:11 +01:00
|
|
|
Zp div (const Zp& d) const { return operator / (d); }
|
2011-12-14 19:07:53 +01:00
|
|
|
|
2016-11-19 20:55:11 +01:00
|
|
|
std::tuple<Zp, Zp, Zp> extended_gcd (const Zp &x) const
|
2011-12-14 19:07:53 +01:00
|
|
|
{
|
|
|
|
if (v)
|
2016-11-19 20:55:11 +01:00
|
|
|
return std::make_tuple (v, Zp (1), Zp (0));
|
2011-12-14 19:07:53 +01:00
|
|
|
else
|
2016-11-19 20:55:11 +01:00
|
|
|
return std::make_tuple (x, Zp (0), Zp (1));
|
2011-12-14 19:07:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Zp gcd (const Zp &x) const
|
|
|
|
{
|
|
|
|
assert (v || x.v);
|
|
|
|
return 1;
|
|
|
|
}
|
2016-11-19 20:55:11 +01:00
|
|
|
friend std::ostream& operator << (std::ostream& os, const Zp& x) {
|
|
|
|
return os << x.v;
|
|
|
|
}
|
|
|
|
static void show_ring () { std::cout << "Z" << p; }
|
|
|
|
void show_self () const { std::cout << v << "(" << p << ")"; }
|
|
|
|
void display_self () const { std::cout << *this << "\n"; }
|
2011-12-14 19:07:53 +01:00
|
|
|
};
|
2016-11-19 20:55:11 +01:00
|
|
|
#endif //KNOTKIT_ALGEBRA_ZP_H
|