Added Zp and unary minus to ring classes. Added *~ to .gitignore.

Added unsigned_extended_gcd.  There are ring/field tests that should
be separated.
This commit is contained in:
Cotton Seed 2011-12-14 13:07:53 -05:00
parent 1d63f2195f
commit 53a139416c
9 changed files with 256 additions and 5 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
*~
*.o
/gss
/main

View File

@ -31,7 +31,8 @@ LIB_HEADERS = lib/lib.h lib/show.h lib/refcount.h lib/pair.h lib/maybe.h lib/vec
lib/unionfind.h lib/priority_queue.h lib/io.h \
lib/directed_multigraph.h
ALGEBRA_HEADERS = algebra/algebra.h algebra/grading.h algebra/module.h \
algebra/Z2.h algebra/linear_combination.h algebra/Z.h algebra/Q.h \
algebra/Z2.h algebra/linear_combination.h \
algebra/Z.h algebra/Zp.h algebra/Q.h \
algebra/polynomial.h algebra/multivariate_polynomial.h \
algebra/laurentpoly.h algebra/fraction_field.h
KNOTKIT_HEADERS = knotkit.h planar_diagram.h dt_code.h knot_diagram.h \

View File

@ -55,6 +55,14 @@ class Z
return Z (STEAL, x);
}
Z operator - () const
{
mpz_t x;
mpz_init (x);
mpz_neg (x, impl->x);
return Z (STEAL, x);
}
Z operator - (const Z &z) const
{
mpz_t x;

View File

@ -27,6 +27,7 @@ class Z2
Z2 operator + (const Z2 &x) const { return Z2 (v ^ x.v); }
Z2 operator - (const Z2 &x) const { return Z2 (v ^ x.v); }
Z2 operator - () const { return *this; }
Z2 operator * (const Z2 &x) const { return Z2 (v & x.v); }
Z2 operator / (const Z2 &x) const { assert (x.v); return *this; }

112
algebra/Zp.h Normal file
View File

@ -0,0 +1,112 @@
template<unsigned p>
class Zp
{
public:
typedef linear_combination<Zp<p> > linear_combination;
typedef linear_combination_const_iter<Zp<p> > linear_combination_const_iter;
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;
}
Zp (const Zp &x) : v(x.v) { }
Zp (copy, const Zp &x) : v(x.v) { }
~Zp () { }
Zp &operator = (const Zp &x) { v = x.v; return *this; }
Zp &operator = (int x)
{
return operator = (Zp (x));
}
bool operator == (const Zp &x) const { return v == x.v; }
bool operator == (int x) const { return operator == (Zp (x)); }
bool operator != (int x) const { return !operator == (x); }
bool operator < (const Zp &x) const { return v < x.v; }
bool is_unit () const
{
return v != 0;
}
Zp operator + (const Zp &x) const { return Zp (v + x.v); }
Zp operator - (const Zp &x) const { return Zp ((int)v - (int)x.v); }
Zp operator - () const { return Zp (- (int)v); }
Zp operator * (const Zp &x) const { return Zp (v * x.v); }
Zp operator / (const Zp &x) const
{
return operator * (x.recip ());
}
Zp recip () const
{
triple<unsigned, int, int> t = unsigned_extended_gcd (v, p);
assert (t.first == 1);
assert ((int)t.first == t.second*(int)v + t.third*(int)p);
return Zp (t.second);
}
Zp &operator += (const Zp &x)
{
v = (v + x.v) % p;
return *this;
}
Zp &operator -= (const Zp &x) { return operator = (Zp ((int)v - (int)x.v)); }
Zp &operator *= (const Zp &x)
{
v = (v * x.v) % p;
return *this;
}
Zp &operator /= (const Zp &x)
{
return operator *= (x.recip ());
}
// d | n, d.divides (n)
bool divides (const Zp &n) const
{
return v || !n.v;
}
bool operator | (const Zp &n) const { return divides (n); }
Zp div (const Zp &d) const { return operator / (d); }
triple<Zp, Zp, Zp> extended_gcd (const Zp &x) const
{
if (v)
return triple<Zp, Zp, Zp> (v, 1, 0);
else
return triple<Zp, Zp, Zp> (x, 0, 1);
}
Zp gcd (const Zp &x) const
{
assert (v || x.v);
return 1;
}
static void show_ring () { printf ("Z%d", p); }
void show_self () const { printf ("%d (%d)", v, p); }
void display_self () const { show_self (); newline (); }
};

View File

@ -40,7 +40,7 @@ int64_gcd (int64 a, int64 b)
}
static triple<unsigned, int, int>
extended_gcd_1 (unsigned a, unsigned b)
extended_gcd_1 (int a, int b)
{
if (b == 0)
return triple<unsigned, int, int> (a, 1, 0);
@ -50,18 +50,24 @@ extended_gcd_1 (unsigned a, unsigned b)
return triple<unsigned, int, int> (b, 0, 1);
else
{
triple<unsigned, int, int> s = extended_gcd (b, t);
triple<unsigned, int, int> s = unsigned_extended_gcd (b, t);
unsigned d = s.first;
int x = s.third,
y = s.second - s.third * (a / b);
assert ((int)d == (int)a*x + (int)b*y);
assert ((int)d == a*x + b*y);
return triple<unsigned, int, int> (d, x, y);
}
}
triple<unsigned, int, int>
unsigned_extended_gcd (unsigned a, unsigned b)
{
return extended_gcd_1 ((int)a, (int)b);
}
triple<unsigned, int, int>
extended_gcd (int a, int b)
{

View File

@ -44,6 +44,8 @@ uint64 int64_lcm (int64 a, int64 b);
// (d, x, y) = gcd (a, b) where x*a + y*b = d
triple<unsigned, int, int> extended_gcd (int a, int b);
triple<unsigned, int, int> unsigned_extended_gcd (unsigned a, unsigned b);
template<class R> class linear_combination;
template<class R> class linear_combination_const_iter;
@ -60,6 +62,7 @@ template<class R> class module;
#include <algebra/linear_combination.h>
#include <algebra/Z.h>
#include <algebra/Zp.h>
#include <algebra/Q.h>
#include <algebra/polynomial.h>

118
main.cpp
View File

@ -1,8 +1,126 @@
#include <knotkit.h>
// test for ring
template<class R> void
test_ring (int p)
{
R zero (0);
R one (1);
R minus_one (-1);
assert (zero == 0);
assert (zero | zero);
assert (one | zero);
assert (minus_one | zero);
assert (! (zero | one));
assert (! (zero | minus_one));
assert (one.is_unit ());
assert (minus_one.is_unit ());
assert (one.recip () == one);
assert (minus_one.recip () == minus_one);
if (p)
assert (R (p) == 0);
if (p != 2)
assert (one != minus_one);
int n = (p
? std::min (p, 20)
: 20);
for (int i = -n; i <= n; i ++)
{
R x (i);
if (x.is_unit ())
{
assert (x * x.recip () == one);
assert (x.recip () * x == one);
assert (x.recip ().recip () == x);
}
assert (one | x);
assert (minus_one | x);
if (x != 0)
{
assert (x | zero);
assert (! (zero | x));
}
for (int j = -n; j <= n; j ++)
{
R y (j);
assert (- (-x) == x);
assert (x + y == y + x);
assert (x * y == y * x);
if (x != 0 && x | y)
{
R q = y.div (x);
assert (y == q * x);
}
if (x != 0 || y != 0)
{
triple<R, R, R> t = x.extended_gcd (y);
assert (t.first == t.second*x + t.third*y);
}
for (int k = -n; k <= n; k ++)
{
R z (k);
assert ((x + y) + z == x + (y + z));
assert ((x * y) * z == x * (y * z));
assert (x*(y + z) == x*y + x*z);
assert ((x + y)*z == x*z + y*z);
}
}
}
}
template<class F> void
test_field ()
{
for (unsigned i = 1; i <= 8; i ++)
for (unsigned j = 1; j <= rolfsen_crossing_knots (i); j ++)
{
knot_diagram kd (rolfsen_knot (i, j));
show (kd); newline ();
cube<F> c (kd);
mod_map<F> d = c.compute_d (1, 0, 0, 0, 0);
assert (d.compose (d) == 0);
ptr<const quotient_module<F> > H = d.homology ();
display ("H:\n", *H);
chain_complex_simplifier<F> s (c.khC, d, 1);
display ("s.new_C:\n", *s.new_C);
assert (H->dim () == s.new_C->dim ());
}
}
int
main ()
{
test_ring<Z2> (2);
test_ring<Z> (0);
test_ring<Zp<2> > (2);
test_ring<Zp<3> > (3);
test_ring<Zp<5> > (5);
test_ring<Zp<7> > (7);
test_field<Zp<7> > ();
test_field<Zp<5> > ();
test_field<Zp<3> > ();
test_field<Z2> ();
test_field<Zp<2> > ();
}

View File

@ -17,10 +17,11 @@ in lib/
in algebra/
- Q should use gmp
- laurentpoly interface needs to be cleand up
- laurentpoly interface needs to be cleaned up
- add Zp
- linear_combnation can be more efficient (eg no searching when
coefficients die)
- monomial ideals and maybe groebner bases
- cleaner interface for gcd, etc. in fraction_field
- support kernel, cokernel of torsion modules
- change gcd et al so gcd is always positive