From 53a139416c83fd1c682170e010b7d66c30317e35 Mon Sep 17 00:00:00 2001 From: Cotton Seed Date: Wed, 14 Dec 2011 13:07:53 -0500 Subject: [PATCH] Added Zp and unary minus to ring classes. Added *~ to .gitignore. Added unsigned_extended_gcd. There are ring/field tests that should be separated. --- .gitignore | 1 + Makefile | 3 +- algebra/Z.h | 8 +++ algebra/Z2.h | 1 + algebra/Zp.h | 112 +++++++++++++++++++++++++++++++++++++++++ algebra/algebra.cpp | 12 +++-- algebra/algebra.h | 3 ++ main.cpp | 118 ++++++++++++++++++++++++++++++++++++++++++++ todo.txt | 3 +- 9 files changed, 256 insertions(+), 5 deletions(-) create mode 100644 algebra/Zp.h diff --git a/.gitignore b/.gitignore index 1cc48b3..620aafd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +*~ *.o /gss /main diff --git a/Makefile b/Makefile index 15d28e2..d64d919 100644 --- a/Makefile +++ b/Makefile @@ -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 \ diff --git a/algebra/Z.h b/algebra/Z.h index 282e867..bd4ee2d 100644 --- a/algebra/Z.h +++ b/algebra/Z.h @@ -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; diff --git a/algebra/Z2.h b/algebra/Z2.h index 50957a3..84e5b12 100644 --- a/algebra/Z2.h +++ b/algebra/Z2.h @@ -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; } diff --git a/algebra/Zp.h b/algebra/Zp.h new file mode 100644 index 0000000..6c6e1ae --- /dev/null +++ b/algebra/Zp.h @@ -0,0 +1,112 @@ + +template +class Zp +{ + public: + typedef linear_combination > linear_combination; + typedef linear_combination_const_iter > 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 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 extended_gcd (const Zp &x) const + { + if (v) + return triple (v, 1, 0); + else + return triple (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 (); } +}; diff --git a/algebra/algebra.cpp b/algebra/algebra.cpp index 2ad11ae..e467674 100644 --- a/algebra/algebra.cpp +++ b/algebra/algebra.cpp @@ -40,7 +40,7 @@ int64_gcd (int64 a, int64 b) } static triple -extended_gcd_1 (unsigned a, unsigned b) +extended_gcd_1 (int a, int b) { if (b == 0) return triple (a, 1, 0); @@ -50,18 +50,24 @@ extended_gcd_1 (unsigned a, unsigned b) return triple (b, 0, 1); else { - triple s = extended_gcd (b, t); + triple 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 (d, x, y); } } +triple +unsigned_extended_gcd (unsigned a, unsigned b) +{ + return extended_gcd_1 ((int)a, (int)b); +} + triple extended_gcd (int a, int b) { diff --git a/algebra/algebra.h b/algebra/algebra.h index 2401135..7634b6e 100644 --- a/algebra/algebra.h +++ b/algebra/algebra.h @@ -44,6 +44,8 @@ uint64 int64_lcm (int64 a, int64 b); // (d, x, y) = gcd (a, b) where x*a + y*b = d triple extended_gcd (int a, int b); +triple unsigned_extended_gcd (unsigned a, unsigned b); + template class linear_combination; template class linear_combination_const_iter; @@ -60,6 +62,7 @@ template class module; #include #include +#include #include #include diff --git a/main.cpp b/main.cpp index c94023c..5aaad92 100644 --- a/main.cpp +++ b/main.cpp @@ -1,8 +1,126 @@ #include +// test for ring + +template 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 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 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 c (kd); + mod_map d = c.compute_d (1, 0, 0, 0, 0); + + assert (d.compose (d) == 0); + + ptr > H = d.homology (); + display ("H:\n", *H); + + chain_complex_simplifier s (c.khC, d, 1); + display ("s.new_C:\n", *s.new_C); + + assert (H->dim () == s.new_C->dim ()); + } +} + int main () { + test_ring (2); + test_ring (0); + test_ring > (2); + test_ring > (3); + test_ring > (5); + test_ring > (7); + test_field > (); + test_field > (); + test_field > (); + test_field (); + test_field > (); } diff --git a/todo.txt b/todo.txt index cbac696..42be4cb 100644 --- a/todo.txt +++ b/todo.txt @@ -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