Skip to content
Browse files

first commit

  • Loading branch information...
0 parents commit da0f41c909859d0a92a19d5964ae057a32b4b41c @johnkerl committed Aug 1, 2012
Showing with 7,865 additions and 0 deletions.
  1. +37 −0 LICENSE.txt
  2. +11 −0 README
  3. +19 −0 T_gm.py
  4. +68 −0 T_tm.py
  5. +26 −0 anc_gm.py
  6. +26 −0 ani_gm.py
  7. +147 −0 cgpalg_dense_tm.py
  8. +199 −0 cgpalg_tm.py
  9. +116 −0 cgtest.py
  10. +22 −0 cl2_gm.py
  11. +139 −0 cl2_tm.py
  12. +22 −0 cl2m_gm.py
  13. +105 −0 cl2m_tm.py
  14. +3 −0 clean
  15. +67 −0 dih_tm.py
  16. +20 −0 dn_gm.py
  17. +37 −0 f2mtest
  18. +408 −0 f2poly_tm.py
  19. +136 −0 f2polymod_tm.py
  20. +44 −0 f2test
  21. +33 −0 fact_m.py
  22. +122 −0 genquat_tm.py
  23. +124 −0 gint_tm.py
  24. +65 −0 ispec_gm.py
  25. +12 −0 ispec_tbl.py
  26. +82 −0 ispec_tm.py
  27. +20 −0 metacyc_gm.py
  28. +183 −0 metacyc_tm.py
  29. +211 −0 mod_tm.py
  30. +33 −0 modadd_gm.py
  31. +110 −0 modadd_tm.py
  32. +74 −0 modmul_gm.py
  33. +133 −0 modmul_tm.py
  34. +220 −0 modtest.py
  35. +45 −0 mvpoly.py
  36. +14 −0 pauli.txt
  37. +20 −0 pauli_gm.py
  38. +148 −0 pauli_tm.py
  39. +613 −0 pmtc_tm.py
  40. +335 −0 pmtc_tm.py.inherit
  41. +534 −0 pmti_tm.py
  42. +22 −0 qn_gm.py
  43. +18 −0 quatu_gm.py
  44. +126 −0 quatu_tm.py
  45. +618 −0 sack
  46. +617 −0 sack.py
  47. +46 −0 sackall_m.py
  48. +64 −0 sackcoset.py
  49. +415 −0 sackgrp.py
  50. +208 −0 sackint.py
  51. +86 −0 sackmisc.py
  52. +10 −0 sackpoly.py
  53. +153 −0 sackprime_m.py
  54. +10 −0 sackrat.py
  55. +39 −0 sackset.py
  56. +57 −0 sacktuple.py
  57. +27 −0 snc_gm.py
  58. +26 −0 sni_gm.py
  59. +56 −0 spec_gm.py
  60. +24 −0 spec_tables.py
  61. +116 −0 spec_tm.py
  62. +66 −0 test_counts
  63. +64 −0 test_cycle_fill.py
  64. +23 −0 test_rand_pmt.py
  65. +76 −0 uniqc_m.py
  66. +18 −0 v4_gm.py
  67. +97 −0 v4_tm.py
37 LICENSE.txt
@@ -0,0 +1,37 @@
+ ================================================================
+ Copyright (c) 2007 John Kerl
+ kerl.john.r@gmail.com
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place, Suite 330, Boston, MA 02111-1307 USA
+ ================================================================
11 README
@@ -0,0 +1,11 @@
+================================================================
+SACK: A simple abstract-algebra calculator. Includes some elementary group
+routines. The main entry point is the script called sack.
+
+For documentation please see http://johnkerl.org/doc/kerl-pyaa.pdf
+
+John Kerl
+kerl.john.r@gmail.com
+Pushed to github 2012-08-01
+Written 2005-ish
+================================================================
19 T_gm.py
@@ -0,0 +1,19 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+import T_tm
+
+def get_elements_str(params_string):
+ elts = []
+ for i in range(0, 3):
+ for j in range(0, 4):
+ elt = T_tm.T_t(i, j)
+ elts.append(elt)
+ return elts
68 T_tm.py
@@ -0,0 +1,68 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+import re
+
+# The T group (the third nonabelian group of order 12, other than A4 and D6)
+# may be thought of as Z3 semidirect Z4, where Z4 acts on Z3 by inversion.
+#
+# (ai, aj)(bi, bj) = (ai aj(bi), aj bj)
+#
+# where aj(bi) is the action of aj on bi.
+
+class T_t:
+ def __init__(self, argi, argj):
+ self.i = argi % 3
+ self.j = argj % 4
+
+ def __eq__(a,b):
+ return ((a.i == b.i) and (a.j == b.j))
+
+ def __ne__(a,b):
+ return not (a == b)
+
+ def __mul__(a,b):
+ ibi = b.i
+ if (a.j & 1):
+ ibi = -ibi
+ ci = (a.i + ibi) % 3
+ cj = (a.j + b.j) % 4
+ c = T_t(ci, cj)
+ return c
+
+ def inv(a):
+ # (ai, aj)(bi, bj) = (ai aj(bi), aj bj) = (0, 0)
+ # Given ai and aj, find bi and bj.
+ bi = (-a.i) % 3
+ if (a.j & 1):
+ bi = a.i % 3
+ bj = (-a.j) % 4
+ b = T_t(bi, bj)
+ return b
+
+ def scan(self, string):
+ groups = re.match(r"^(\d)+,(\d+)$", string).groups();
+ if len(groups) != 2:
+ raise IOError
+ self.__init__(int(groups[0]), int(groups[1]))
+
+ def __str__(self):
+ return str(self.i) + "," + str(self.j)
+
+ def __repr__(self):
+ return self.__str__()
+
+def params_from_string(params_string):
+ return 0
+
+def from_string(value_string, params_string):
+ obj = T_t(0, 0)
+ obj.scan(value_string)
+ return obj
26 anc_gm.py
@@ -0,0 +1,26 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+import pmtc_tm
+import sackint
+
+def get_elements(n):
+ sn_size = sackint.factorial(n)
+ elts = []
+ for k in range(0, sn_size):
+ elt = pmtc_tm.kth_pmtc(k, n, sn_size)
+ if (elt.parity() == 0):
+ elts.append(elt)
+ pmtc_tm.sort_pmtcs(elts)
+ return elts
+
+def get_elements_str(params_string):
+ n = pmtc_tm.params_from_string(params_string)
+ return get_elements(n)
26 ani_gm.py
@@ -0,0 +1,26 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+import pmti_tm
+import sackint
+
+def get_elements(n):
+ sn_size = sackint.factorial(n)
+ elts = []
+ for k in range(0, sn_size):
+ elt = pmti_tm.kth_pmti(k, n, sn_size)
+ if (elt.parity() == 0):
+ elts.append(elt)
+ pmti_tm.sort_pmtis(elts)
+ return elts
+
+def get_elements_str(params_string):
+ n = pmti_tm.params_from_string(params_string)
+ return get_elements(n)
147 cgpalg_dense_tm.py
@@ -0,0 +1,147 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+import sys
+import re
+import copy
+
+# ================================================================
+# Initial attempt at complex group algebras CG for small finite groups G. This
+# could, conceivably, be generalized to FG (for arbitrary user-specified
+# fields) or RG (for arbitrary user-specified rings).
+#
+# There are two possible storage representations for an element of CG:
+# * Sparse: Keep a list of non-zero coefficients, with their
+# corresponding group elements.
+# * Dense: Keep a list of group elements, with another list of coefficients.
+#
+# For now I will attempt the latter. Good hygiene would require me to make
+# the following checks (which I will not):
+# * A's coef-array length = A's group-elements-array length
+# * B's coef-array length = B's group-elements-array length
+# * A's coef-array length = B's coef-array length
+# * A's group-elements-array length = B's group-elements-array length
+#
+# ================================================================
+# John Kerl
+# 2007-05-08
+# ================================================================
+
+class cgpalg_t:
+ def __init__(self, coef_array, gp_elt_array):
+ #self.check_lengths(len(coef_array), len(gp_elt_array), "coefs", "gp_elts")
+ self.coefs = copy.copy(coef_array)
+ self.gp_elts = copy.copy(gp_elt_array)
+
+ def __add__(a,b):
+ #a.check_lengths(len(a.gp_elts), len(b.gp_elts), "coefs", "gp_elts")
+ c = cgpalg_t(a.coefs, a.gp_elts)
+ for i in range (0, len(a.coefs)):
+ c.coefs[i] = a.coefs[i] + b.coefs[i]
+ return c
+
+ def __sub__(a,b):
+ #a.check_lengths(len(a.gp_elts), len(b.gp_elts), "coefs", "gp_elts")
+ c = cgpalg_t(a.coefs, a.gp_elts)
+ for i in range (0, len(a.coefs)):
+ c.coefs[i] = a.coefs[i] - b.coefs[i]
+ return c
+
+ def index_of(self, g):
+ for k in range(0, len(self.gp_elts)):
+ if (g == self.gp_elts[k]):
+ return k
+ print "cgpalg_t: Couldn't find [", g, "] in gp_elts array."
+ sys.exit(1)
+
+ def __mul__(a,b):
+ #a.check_lengths(len(a.gp_elts), len(b.gp_elts), "coefs", "gp_elts")
+ c = cgpalg_t(a.coefs, a.gp_elts)
+ # XXX XXX XXX
+ zero = a.coefs[0] - a.coefs[0]
+ for i in range (0, len(a.coefs)):
+ c.coefs[i] = zero
+ for i in range (0, len(a.coefs)):
+ for j in range (0, len(b.coefs)):
+ k = c.index_of(a.gp_elts[i] * b.gp_elts[j])
+ c.coefs[k] += a.coefs[i] * b.coefs[j]
+ return c
+
+ def __eq__(a,b):
+ if (len(a.coefs) != len(b.coefs)):
+ return 0
+ n = len(a.coefs)
+ for i in range(0, n):
+ if (a.coefs[i] != b.coefs[i]):
+ return 0
+ return 1
+
+ def __ne__(a,b):
+ return not (a == b)
+
+ def __neg__(a):
+ c = cgpalg_t(a.coefs, a.gp_elts)
+ for i in range(0, len(a.gp_elts)):
+ c.coefs[i] = -a.coefs[i]
+ return c
+
+# def scan(self, res_string, cgpalg_array):
+# res_strings = re.split(',', res_string)
+# #self.check_lengths(len(res_strings), len(cgpalg_array), res_strings,
+# str(cgpalg_strings))
+# n = len(res_strings)
+# coef_array = range(0, n)
+# for i in range(0, n):
+# coef_array[i] = int(res_strings[i])
+# self.__init__(coef_array, gp_elt_array)
+
+ def __str__(self):
+ string = ""
+ for i in range(0, len(self.coefs)):
+ if (i > 0):
+ string += " "
+ string += "["
+ string += str(self.coefs[i])
+ string += "]*["
+ string += str(self.gp_elts[i])
+ string += "]"
+ return string
+
+ def __repr__(self):
+ return self.__str__()
+
+# def check_length(self, length, desc):
+# if (length < 1):
+# print desc, "length", str(length), "< 1"
+# raise RuntimeError
+
+# def check_lengths(self, len1, len2, desc1, desc2):
+# self.check_length(len1, desc1)
+# self.check_length(len2, desc2)
+# if (len1 != len2):
+# print desc1, "length", str(len1), "!=", desc2, "length", len2
+# raise RuntimeError
+
+#def params_from_string(params_string):
+# if (len(params_string) == 0):
+# print "Modadd requires non-empty parameter string"
+# sys.exit(1)
+# cgpalg_strings = re.split(',', params_string)
+# n = len(cgpalg_strings)
+# cgpalg_array = range(0, n)
+# for i in range(0, n):
+# cgpalg_array[i] = int(cgpalg_strings[i])
+# return cgpalg_array
+
+#def from_string(value_string, params_string):
+# cgpalg_array = params_from_string(params_string)
+# obj = cgpalg_t([1], [1])
+# obj.scan(value_string, cgpalg_array)
+# return obj
199 cgpalg_tm.py
@@ -0,0 +1,199 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+import sys
+import re
+import copy
+
+# ================================================================
+# Initial attempt at complex group algebras CG for small finite groups G. This
+# could, conceivably, be generalized to FG (for arbitrary user-specified
+# fields) or RG (for arbitrary user-specified rings).
+#
+# There are two possible storage representations for an element of CG:
+# * Sparse: Keep a list of non-zero coefficients, with their
+# corresponding group elements.
+# * Dense: Keep a list of group elements in each algebra element, with
+# another list of coefficients.
+#
+# For now I will attempt the former. A "pair" is a two-element list of
+# coefficient and group element; an algebra element is a list of pairs.
+#
+# ================================================================
+# John Kerl
+# 2007-05-08
+# ================================================================
+
+class cgpalg_t:
+
+ def __init__(self, pairs_array):
+ self.pairs = copy.deepcopy(pairs_array)
+
+ def index_of(self, g):
+ for k in range(0, len(self.pairs)):
+ if (g == self.pairs[k][1]):
+ return [1, k]
+ return [0, 0]
+
+ def zero_strip(self):
+ untested = self.pairs
+ self.pairs = []
+ while (untested):
+ x = untested[0]
+ untested = untested[1:]
+ if (x[0] != 0):
+ self.pairs += [x]
+
+ # I am using sparse storage. However, this routine permits a dense
+ # extraction of coefficients: Given an array of group elements, it
+ # returns a list of coefficients (in the same order).
+ #
+ # This makes it possible to hand the results off to a linear-algebra
+ # routine.
+ def to_coef_array(self, group_elements):
+ coefs = []
+ for g in group_elements:
+ coef = 0
+ [found, k] = self.index_of(g)
+ if (found):
+ coef = self.pairs[k][0]
+ coefs += [coef]
+ return coefs
+
+ def __add__(a,b):
+ # Concatenate the two lists. Then merge the pairs with matching
+ # group elements.
+ c = cgpalg_t([])
+ unmerged_pairs = copy.deepcopy(a.pairs + b.pairs)
+ while (unmerged_pairs):
+ current_pair = unmerged_pairs[0]
+ [found, k] = c.index_of(current_pair[1])
+ if (found):
+ # Update
+ c.pairs[k][0] += current_pair[0]
+ else:
+ # Insert
+ c.pairs += [current_pair]
+ unmerged_pairs = unmerged_pairs[1:]
+ return c
+
+ def __neg__(b):
+ negb = cgpalg_t(b.pairs)
+ for k in range(0, len(negb.pairs)):
+ negb.pairs[k][0] = -negb.pairs[k][0]
+ return negb
+
+ def __sub__(a,b):
+ return a + (-b)
+
+ def __mul__(a,b):
+ c = cgpalg_t([])
+ for ap in a.pairs:
+ for bp in b.pairs:
+ ccoef = ap[0] * bp[0] # Field multiplication
+ cgpelt = ap[1] * bp[1] # Group multiplication
+ [found, k] = c.index_of(cgpelt)
+ if (found):
+ # Update
+ c.pairs[k][0] += ccoef
+ else:
+ # Insert
+ c.pairs += [[ccoef, cgpelt]]
+ c.zero_strip()
+ return c
+
+ # The group data type must support the inv() method.
+ # This is a stub for correct implementation and doesn't work (except for singletons).
+ def inv(self):
+ bi = cgpalg_t([])
+ n = len(self.pairs)
+ if (n == 0):
+ print "cgpalg_t.inv: division by zero."
+ sys.exit(1)
+ recip_n = 1.0/n
+ for pair in self.pairs:
+ bi.pairs += [[recip_n/pair[0], pair[1].inv()]]
+ return bi
+
+ def __div__(a,b):
+ return a * b.inv()
+
+# def __eq__(a,b):
+# if (len(a.pairs) != len(b.pairs)):
+# return 0
+# n = len(a.coefs)
+# for i in range(0, n):
+# if (a.coefs[i] != b.coefs[i]):
+# return 0
+# return 1
+
+# def __ne__(a,b):
+# return not (a == b)
+
+# def scan(self, res_string, cgpalg_array):
+# res_strings = re.split(',', res_string)
+# #self.check_lengths(len(res_strings), len(cgpalg_array), res_strings,
+# str(cgpalg_strings))
+# n = len(res_strings)
+# coef_array = range(0, n)
+# for i in range(0, n):
+# coef_array[i] = int(res_strings[i])
+# self.__init__(coef_array, gp_elt_array)
+
+ def __str__(self):
+ string = ""
+ if (len(self.pairs) == 0):
+ string = "0"
+ for i in range(0, len(self.pairs)):
+ if (i > 0):
+ string += " "
+ string += "["
+ string += str(self.pairs[i][0])
+ string += "]*["
+ string += str(self.pairs[i][1])
+ string += "]"
+ return string
+
+ def __repr__(self):
+ return self.__str__()
+
+# Construct an element of C S_n, given only a list of permutations: each
+# coefficient is 1.
+def from_pmtns(pmtn_array):
+ pairs = []
+ for pmtn in pmtn_array:
+ pairs += [[1, pmtn]]
+ return cgpalg_t(pairs)
+
+# Construct an element of C S_n, given only a list of permutations: compute the
+# coefficient from the parity. The group class being used must support the
+# sgn() method.
+def from_pmtns_with_parity(pmtn_array):
+ pairs = []
+ for pmtn in pmtn_array:
+ pairs += [[pmtn.sgn(), pmtn]]
+ return cgpalg_t(pairs)
+
+#def params_from_string(params_string):
+# if (len(params_string) == 0):
+# print "Modadd requires non-empty parameter string"
+# sys.exit(1)
+# cgpalg_strings = re.split(',', params_string)
+# n = len(cgpalg_strings)
+# cgpalg_array = range(0, n)
+# for i in range(0, n):
+# cgpalg_array[i] = int(cgpalg_strings[i])
+# return cgpalg_array
+
+#def from_string(value_string, params_string):
+# cgpalg_array = params_from_string(params_string)
+# obj = cgpalg_t([1], [1])
+# obj.scan(value_string, cgpalg_array)
+# return obj
116 cgtest.py
@@ -0,0 +1,116 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+import pmtc_tm
+import snc_gm
+import cgpalg_tm
+import copy
+
+# ----------------------------------------------------------------
+# 559B final problem 1a.
+
+print "-" * 64
+
+#S3 = snc_gm.get_elements(3)
+
+s1 = pmtc_tm.from_cycle([1], 3)
+s12 = pmtc_tm.from_cycle([1,2], 3)
+s13 = pmtc_tm.from_cycle([1,3], 3)
+s23 = pmtc_tm.from_cycle([2,3], 3)
+s123 = pmtc_tm.from_cycle([1,2,3], 3)
+s132 = pmtc_tm.from_cycle([1,3,2], 3)
+S3 = [s1, s12, s13, s23, s123, s132]
+
+s1 = pmtc_tm.from_cycle([1], 3)
+s12 = pmtc_tm.from_cycle([1,2], 3)
+s13 = pmtc_tm.from_cycle([1,3], 3)
+
+P = cgpalg_tm.cgpalg_t([[1,s1], [ 1,s12]])
+Q = cgpalg_tm.cgpalg_t([[1,s1], [-1,s13]])
+E = P*Q
+
+print "S3:"
+for g in S3:
+ print g
+print ""
+
+print "P:", P
+print "Q:", Q
+print "E:", E
+print "E*E", E*E
+print
+
+#print "AEs:"
+#for g in S3:
+# A = cgpalg_tm.cgpalg_t([[1, g]])
+# AE = A * E
+# print AE
+#print
+
+print "AEs:"
+for g in S3:
+ A = cgpalg_tm.cgpalg_t([[1, g]])
+ AE = A * E
+ #print g, "--", AE.to_coef_array(S3)
+ print AE.to_coef_array(S3)
+print
+# Got rank 2
+
+print "AE invs:"
+for g in S3:
+ A = cgpalg_tm.cgpalg_t([[1, g]])
+ AE = A * E
+ #print g, "--", AE.to_coef_array(S3)
+ print AE.inv()
+print
+# Got rank 2
+
+print "AE inv checks:"
+for g in S3:
+ A = cgpalg_tm.cgpalg_t([[1, g]])
+ AE = A * E
+ #print g, "--", AE.to_coef_array(S3)
+ print AE.inv() * AE
+print
+# Got rank 2
+
+# ----------------------------------------------------------------
+# 559B final problem 1b.
+
+print "-" * 64
+
+S4 = snc_gm.get_elements(4)
+
+s1 = pmtc_tm.from_cycle([1], 4)
+s12 = pmtc_tm.from_cycle([1,2], 4)
+
+s13 = pmtc_tm.from_cycle([1,3], 4)
+s14 = pmtc_tm.from_cycle([1,4], 4)
+s34 = pmtc_tm.from_cycle([3,4], 4)
+s134 = pmtc_tm.from_cycle([1,3,4], 4)
+s143 = pmtc_tm.from_cycle([1,4,3], 4)
+
+P = cgpalg_tm.from_pmtns([s1, s12])
+Q = cgpalg_tm.from_pmtns_with_parity([s1, s13, s14, s34, s134, s143])
+E = P*Q
+print "P:", P
+print "Q:", Q
+print "E:", E
+print "E*E", E*E
+print
+
+print "AEs:"
+for g in S4:
+ A = cgpalg_tm.cgpalg_t([[1, g]])
+ AE = A * E
+ print AE.to_coef_array(S4)
+print
+# Got rank 3
+
22 cl2_gm.py
@@ -0,0 +1,22 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+import cl2_tm
+
+def get_elements_str(params_string):
+ [n, sqsign] = cl2_tm.params_from_string(params_string)
+ two_n = 1 << n
+ elts = []
+ for bits in range(0, two_n):
+ for sign in [1, -1]:
+ #for sign in [1, -1]:
+ #for bits in range(0, two_n):
+ elts.append(cl2_tm.cl2_t(sign, bits, n, sqsign))
+ return elts
139 cl2_tm.py
@@ -0,0 +1,139 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+import re
+import copy # xxx temp
+
+# The Clifford group with (hard-coded) Simon's quadratic form.
+# See Simon's text.
+#
+# alpha eA beta eB = alpha beta chi(A, B) e{A xor B}.
+# A and B are multi-indices; alpha and beta are signs.
+#
+# Explanation of chi(A, B) is by example:
+#
+# * a = e2 e3 e6 e7; b = e1 e3 e5 e6.
+# * a*b = e2 e3 e6 e7 | e1 e3 e5 e6. Then sort:
+# - Move e1 left: e1 e2 e3 e6 e7|e3 e5 e6, passing a's e2, e3, e6, e7.
+# - move e3 left: e1 e2 e3 e3 e6 e7|e5 e6, passing a's e6 and e7.
+# - Move e5 left: e1 e2 e3 e3 e5 e6 e7|e6, passing a's e6 and e7.
+# - Move e5 left: e1 e2 e3 e3 e5 e6 e6 e7, passing a's e7.
+#
+# If sqsign == -1, then ei*ei = -1, else ei*ei = +1.
+# One can imagine implementing more general quadratic forms: not yet. :)
+
+class cl2_t:
+
+ def __init__(self, sign, bits, n, sqsign):
+ self.sign = sign
+ self.bits = bits & ((1 << n) - 1)
+ self.n = n
+ self.sqsign = sqsign
+
+ def __mul__(a,b):
+ c = cl2_t(a.sign * b.sign, a.bits ^ b.bits, a.n, a.sqsign)
+ for j in range(0, b.n):
+ if ((b.bits >> j) & 1):
+ # Count the number of times to move this element of b left
+ # past elements of a.
+ #
+ # If sqsign == -1, then ei*ei = -1, else ei*ei = +1.
+ lolim = j+1
+ if (a.sqsign == -1):
+ lolim = j
+ for i in range(lolim, a.n):
+ if ((a.bits >> i) & 1):
+ c.sign *= -1
+ return c
+
+ def __eq__(a,b):
+ return (a.sign == b.sign and a.bits == b.bits and a.n == b.n and a.sqsign == b.sqsign)
+
+ def __ne__(a,b):
+ return not (a == b)
+
+ def __lt__(a,b):
+ if (a.bits < b.bits):
+ return 1
+ return a.sign > b.sign
+ def __le__(a,b):
+ if (a.bits <= b.bits):
+ return 1
+ return a.sign >= b.sign
+ def __gt__(a,b):
+ if (a.bits > b.bits):
+ return 1
+ return a.sign < b.sign
+ def __ge__(a,b):
+ if (a.bits >= b.bits):
+ return 1
+ return a.sign <= b.sign
+
+ def inv(a):
+ c = copy.copy(a)
+ return c
+
+ def scan(self, string):
+ if (1):
+ self.__init__(1, 0, 4) # stub
+ else:
+ raise IOError
+
+ def __str__(self):
+ rv = "+"
+ if (self.sign < 0):
+ rv = "-"
+ for i in range(0, self.n):
+ rv += str((self.bits >> i) & 1)
+ return rv
+
+ def __repr__(self):
+ return self.__str__()
+
+def params_from_string(params_string):
+ n = 0
+ sqsign = 1
+ fields = re.split(',', params_string)
+ ok = 1
+
+ if (len(fields) == 2):
+ n = int(fields[0])
+ if (fields[1] == "+"):
+ sqsign = 1
+ elif (fields[1] == "+1"):
+ sqsign = 1
+ elif (fields[1] == "1"):
+ sqsign = 1
+ elif (fields[1] == "-"):
+ sqsign = -1
+ elif (fields[1] == "-1"):
+ sqsign = -1
+ else:
+ ok = 0
+ else:
+ ok = 0
+
+ if (not ok):
+ print "cl2_tm.from_string: expected parameters n,sign."
+ print "Got: ", params_string
+ raise IOError
+ return [n, sqsign]
+
+
+def from_string(value_string, params_string):
+ [n, sqsign] = params_from_string(params_string)
+ obj = cl2_t(1, 0, n, sqsign)
+ obj.scan(value_string)
+ return obj
+
+## xxx temp
+#a = cl2_t(1, 0x66, 8)
+#b = cl2_t(1, 0x35, 8)
+#c = a * b
22 cl2m_gm.py
@@ -0,0 +1,22 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+import cl2m_tm
+
+def get_elements_str(params_string):
+ n = cl2m_tm.params_from_string(params_string)
+ two_n = 1 << n
+ elts = []
+ #for bits in range(0, two_n):
+ #for sign in [1, -1]:
+ for sign in [1, -1]:
+ for bits in range(0, two_n):
+ elts.append(cl2m_tm.cl2m_t(sign, bits, n))
+ return elts
105 cl2m_tm.py
@@ -0,0 +1,105 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+import re
+import copy # xxx temp
+
+# The Clifford group with (hard-coded) negative of Simon's quadratic form.
+# See Simon's text.
+#
+# alpha eA beta eB = alpha beta chi(A, B) e{A xor B}.
+# But also with ei^2 = -1.
+# A and B are multi-indices; alpha and beta are signs.
+#
+# Explanaiton of chi(A, B) is by example:
+#
+# * a = e2 e3 e6 e7; b = e1 e3 e5 e6.
+# * a*b = e2 e3 e6 e7 | e1 e3 e5 e6. Then sort:
+# - Move e1 left: e1 e2 e3 e6 e7|e3 e5 e6, passing a's e2, e3, e6, e7.
+# - move e3 left: e1 e2 e3 e3 e6 e7|e5 e6, passing a's e6 and e7.
+# - Move e5 left: e1 e2 e3 e3 e5 e6 e7|e6, passing a's e6 and e7.
+# - Move e5 left: e1 e2 e3 e3 e5 e6 e6 e7, passing a's e7.
+
+class cl2m_t:
+
+ def __init__(self, sign, bits, n):
+ self.sign = sign
+ self.bits = bits & ((1 << n) - 1)
+ self.n = n
+
+ def __mul__(a,b):
+ c = cl2m_t(a.sign * b.sign, a.bits ^ b.bits, a.n)
+ for j in range(0, b.n):
+ if ((b.bits >> j) & 1):
+ # Count the number of times to move this element of b left
+ # past elements of a.
+ for i in range(j, a.n):
+ if ((a.bits >> i) & 1):
+ c.sign *= -1
+ return c
+
+ def __eq__(a,b):
+ return (a.sign == b.sign and a.bits == b.bits and a.n == b.n)
+
+ def __ne__(a,b):
+ return not (a == b)
+
+ def __lt__(a,b):
+ if (a.bits < b.bits):
+ return 1
+ return a.sign > b.sign
+ def __le__(a,b):
+ if (a.bits <= b.bits):
+ return 1
+ return a.sign >= b.sign
+ def __gt__(a,b):
+ if (a.bits > b.bits):
+ return 1
+ return a.sign < b.sign
+ def __ge__(a,b):
+ if (a.bits >= b.bits):
+ return 1
+ return a.sign <= b.sign
+
+ def inv(a):
+ c = copy.copy(a) # stub -- NOT right.
+ return c
+
+ def scan(self, string):
+ if (1):
+ self.__init__(1, 0, 4) # stub
+ else:
+ raise IOError
+
+ def __str__(self):
+ rv = "+"
+ if (self.sign < 0):
+ rv = "-"
+ for i in range(0, self.n):
+ rv += str((self.bits >> i) & 1)
+ return rv
+
+ def __repr__(self):
+ return self.__str__()
+
+def params_from_string(params_string):
+ n = int(params_string)
+ return n
+
+def from_string(value_string, params_string):
+ n = params_from_string(params_string)
+ obj = cl2m_t(1, 0, n)
+ obj.scan(value_string)
+ return obj
+
+## xxx temp
+#a = cl2m_t(1, 0x66, 8)
+#b = cl2m_t(1, 0x35, 8)
+#c = a * b
3 clean
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+rm -f *.pyc
67 dih_tm.py
@@ -0,0 +1,67 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+import re
+
+class dih_t:
+ #rot = 0
+ #flip = 0
+ #n = 0
+
+ def __init__(self, argrot, argflip, argn):
+ self.n = argn
+ self.rot = argrot % self.n
+ self.flip = argflip & 1
+
+ def __eq__(a,b):
+ return ((a.rot == b.rot) and (a.flip == b.flip))
+
+ def __ne__(a,b):
+ return not (a == b)
+
+ def __mul__(a,b):
+ if (a.n != b.n):
+ raise RuntimeError
+ if (a.flip):
+ crot = a.rot - b.rot
+ else:
+ crot = a.rot + b.rot
+ c = dih_t(crot, a.flip ^ b.flip, a.n)
+ return c
+
+ def inv(a):
+ if (a.flip):
+ c = dih_t(a.rot, a.flip, a.n)
+ return c
+ else:
+ c = dih_t(a.n - a.rot, a.flip, a.n)
+ return c
+
+ def scan(self, string, argn):
+ groups = re.match(r"^(\d)+,(\d+)$", string).groups();
+ if len(groups) != 2:
+ raise IOError
+ self.__init__(int(groups[0]), int(groups[1]), argn)
+
+ def __str__(self):
+ return str(self.rot) + "," + str(self.flip)
+
+ def __repr__(self):
+ return self.__str__()
+
+def params_from_string(params_string):
+ n = int(params_string)
+ return n
+
+def from_string(value_string, params_string):
+ n = params_from_string(params_string)
+ obj = dih_t(0, 0, n)
+ obj.scan(value_string, n)
+ return obj
20 dn_gm.py
@@ -0,0 +1,20 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+import dih_tm
+
+def get_elements_str(params_string):
+ n = dih_tm.params_from_string(params_string)
+ elts = []
+ for i in range(0, n):
+ for j in range(0, 2):
+ elt = dih_tm.dih_t(i, j, n)
+ elts.append(elt)
+ return elts
37 f2mtest
@@ -0,0 +1,37 @@
+#!/usr/bin/python -Wall
+
+from f2poly_tm import *
+from f2polymod_tm import *
+import sys
+
+ar = f2poly_t(0xa)
+br = f2poly_t(0xb)
+m = f2poly_t(0x13)
+e = 3
+argc = len(sys.argv)
+if (argc == 4):
+ m = f2poly_from_string(sys.argv[1])
+ ar = f2poly_from_string(sys.argv[2])
+ br = f2poly_from_string(sys.argv[3])
+if (argc == 5):
+ m = f2poly_from_string(sys.argv[1])
+ ar = f2poly_from_string(sys.argv[2])
+ br = f2poly_from_string(sys.argv[3])
+ e = int(sys.argv[4])
+a = f2polymod_t(ar, m)
+b = f2polymod_t(br, m)
+print "a =", a
+print "b =", b
+
+s = a + b
+d = a - b
+p = a * b
+q = a / b
+print "a =", a
+print "b =", b
+print "sum =", s
+print "diff =", d
+print "prod =", p
+print "quot =", q
+print a, "**", e, "=", a**e
+
408 f2poly_tm.py
@@ -0,0 +1,408 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2008-11-14
+# ================================================================
+
+import sys
+import re
+import copy
+
+# ================================================================
+def f2poly_from_string(string):
+ return f2poly_t(int(string, 16))
+
+def idegree(bits):
+ if (bits == 0):
+ return 0 # The zero polynomial has degree zero by fiat.
+ rv = -1
+ while bits:
+ rv += 1
+ bits >>= 1
+ return rv
+
+def imul(abits, bbits):
+ cbits = 0
+ shift = 0
+ while bbits:
+ if bbits & 1:
+ cbits ^= abits << shift
+ bbits >>= 1
+ shift += 1
+ return cbits
+
+# ----------------------------------------------------------------
+# iquot_and_rem
+# Returns [quotient, remainder].
+# ----------------------------------------------------------------
+# E.g.
+# dividend = 1,2,3,4 (1 + 2x + 3x^2 + 4x^3)
+# divisor = 1,1,2 (1 + x + 2x^2)
+# modulus = 7
+#
+# q=4,2 r = 4,3
+# +----------
+# 1,1,2 | 1,2,3,4
+# | 2,2,4 shift = 1. 4/2 mod 7 = 2. 1,1,2 * 2 = 2,2,4.
+# +----------
+# | 1 0 1
+# | 4 4 1 shift = 0. 1/2 mod 7 = 4 1,1,2 * 4 = 4,4,1
+# +----------
+# | 4 3
+#
+# ----------------------------------------------------------------
+
+def iquot_and_rem(abits, bbits):
+ if bbits == 0: # Divisor is zero.
+ print >> sys.stderr, "f2poly_tm.iquot_and_rem: Divide by zero."
+ sys.exit(1)
+ divisor_l1_pos = idegree(bbits)
+
+ if abits == 0: # Dividend is zero.
+ return [0, 0]
+ dividend_l1_pos = idegree(abits)
+
+ l1_diff = dividend_l1_pos - divisor_l1_pos
+ if l1_diff < 0: # Dividend has lower degree than divisor.
+ return [0, abits]
+
+ shift_divisor = bbits << l1_diff
+ quotbits = 0
+ rembits = abits
+ check_pos = dividend_l1_pos
+ quot_pos = l1_diff
+ while check_pos >= divisor_l1_pos:
+ # if f2poly_bit_at(rembits, check_pos)
+ if rembits & (1 << check_pos):
+ rembits ^= shift_divisor
+ # f2poly_set_bit(quotbits, quot_pos)
+ quotbits |= 1 << quot_pos
+ shift_divisor >>= 1
+ check_pos -= 1
+ quot_pos -= 1
+
+ return [quotbits, rembits]
+
+# ----------------------------------------------------------------
+# This is quot_and_rem, but doesn't track the quotient. This saves a few
+# cycles for finite-field arithmetic.
+
+def imod(abits, bbits):
+ if bbits == 0: # Divisor is zero.
+ print >> sys.stderr, "f2poly_tm.iquot_and_rem: Divide by zero."
+ sys.exit(1)
+ divisor_l1_pos = idegree(bbits)
+
+ if abits == 0: # Dividend is zero.
+ return 0
+ dividend_l1_pos = idegree(abits)
+
+ l1_diff = dividend_l1_pos - divisor_l1_pos
+ if l1_diff < 0: # Dividend has lower degree than divisor.
+ return abits
+
+ shift_divisor = bbits << l1_diff
+ rembits = abits
+ check_pos = dividend_l1_pos
+ quot_pos = l1_diff
+ while check_pos >= divisor_l1_pos:
+ # if f2poly_bit_at(rembits, check_pos)
+ if rembits & (1 << check_pos):
+ rembits ^= shift_divisor
+ shift_divisor >>= 1
+ check_pos -= 1
+ quot_pos -= 1
+
+ return rembits
+
+# ----------------------------------------------------------------
+def iexp(abits, e):
+ deg = idegree(abits)
+ ap = abits
+ rv = 1
+
+ if abits == 0:
+ if e == 0:
+ print >> sys.stderr, "f2poly_t.iexp: 0 ^ 0 undefined."
+ sys.exit(1)
+ elif e < 0:
+ print >> sys.stderr, "f2poly_t.iexp: division by zero."
+ sys.exit(1)
+ else:
+ return 0
+ elif deg == 0: # Unit
+ return 1
+ else: # Degree 1 or higher.
+ if e < 0:
+ print >> sys.stderr, "f2poly_t.iexp: division by non-unit."
+ sys.exit(1)
+ else:
+ while e != 0:
+ if e & 1:
+ rv *= ap
+ e = e >> 1
+ ap *= ap
+ return rv
+
+# ----------------------------------------------------------------
+def igcd(abits, bbits):
+ if abits == 0: return bbits
+ if bbits == 0: return abits
+
+ cbits = abits
+ dbits = bbits
+ while True:
+ [qbits, rbits] = iquot_and_rem(cbits, dbits)
+ if rbits == 0:
+ break
+ cbits = dbits
+ dbits = rbits
+ return dbits
+
+# ----------------------------------------------------------------
+# xxx b0rk3n: f2test 3 6
+
+# Blankinship's algorithm.
+# Returns [g, r, s] where g = ar + bs.
+def iext_gcd(abits, bbits):
+ if (abits == 0):
+ return [bbits, 0, 1]
+ if (bbits == 0):
+ return [abits, 1, 0]
+
+ rprime = 1
+ s = 1
+ r = 0
+ sprime = 0
+ c = abits
+ d = bbits
+
+ while 1:
+ [q, r] = iquot_and_rem(c, d)
+ # Note: now c = qd + r and 0 <= r < d
+ if r == 0:
+ break
+ c = d
+ d = r
+
+ t = rprime
+ rprime = r
+ qr = imul(q, r)
+ r = t ^ qr
+
+ t = sprime
+ sprime = s
+ qs = imul(q, s)
+ s = t ^ qs
+
+ return [d, r, s]
+
+# ================================================================
+class f2poly_t:
+ def __init__(self, bits):
+ self.bits = bits
+
+ def __add__(a,b):
+ c = f2poly_t(a.bits ^ b.bits)
+ return c
+ def __sub__(a,b):
+ c = f2poly_t(a.bits ^ b.bits)
+ return c
+
+ # This helps avoid infinite shift loops.
+ # xxx mv to an ifunc
+ def check_unsigned_bits(self):
+ if self.bits < 0:
+ print >> sys.stderr, \
+ "f2poly_t: signed input %d detected." % (self.bits)
+ sys.exit(1)
+ return self.bits
+
+ def degree(self):
+ return idegree(self.check_unsigned_bits())
+
+ def __mul__(a,b):
+ bbits = b.check_unsigned_bits()
+ return f2poly_t(imul(a.bits, bbits))
+
+ def __div__(a,b):
+ [qbits, rbits] = iquot_and_rem(a.bits, b.bits)
+ return f2poly_t(qbits)
+
+ def __mod__(a,b):
+ [qbits, rbits] = iquot_and_rem(a.bits, b.bits)
+ return f2poly_t(rbits)
+
+ def __pow__(a, e):
+ return f2poly_t(iexp(a.bits, e))
+
+ def gcd(a, b):
+ return f2poly_t(igcd(a.bits, b.bits))
+
+ # ----------------------------------------------------------------
+ # Blankinship's algorithm.
+ # Returns [g, r, s] where g = ar + bs.
+ def ext_gcd(a, b):
+ [gbits, rbits, sbits] = iext_gcd(a.bits, b.bits)
+ return [f2poly_t(gbits), f2poly_t(rbits), f2poly_t(sbits)]
+
+ def __eq__(a,b):
+ return a.bits == b.bits
+ def __ne__(a,b):
+ return not (a == b)
+ def __neg__(a):
+ return a
+
+ def scan(self, string):
+ self.bits = int(string, 16)
+
+ def __str__(self):
+ return "0x%x" % self.bits
+ #return "%x" % self.bits
+ def __repr__(self):
+ return self.__str__()
+
+#inline f2poly_t f2poly_t::prime_sfld_elt(int v) const
+#
+# f2poly_t rv(v & 1)
+# return rv
+
+#inline int f2poly_t::get_char(void)
+#
+# return 2
+
+#inline f2poly_t f2poly_t::deriv(void)
+#
+# f2poly_t rv = *this
+# rv.bits >>= 1
+# rv.bits &= 0x55555555
+# return rv
+
+#inline int f2poly_t::operator< (f2poly_t that) const
+#
+# return this->bits < that.bits
+#
+#inline int f2poly_t::operator> (f2poly_t that) const
+#
+# return this->bits > that.bits
+#
+#inline int f2poly_t::operator<=(f2poly_t that) const
+#
+# return this->bits <= that.bits
+#
+#inline int f2poly_t::operator>=(f2poly_t that) const
+#
+# return this->bits >= that.bits
+#
+#inline void f2poly_t::increment(void)
+#
+# this->bits++
+
+#inline void f2poly_t::set_coeff(int deg, bit_t b)
+#
+# this->bounds_check(deg)
+# if b.get_residue():
+# this->bits |= 1 << deg
+# else
+# this->bits &= ~(1 << deg)
+
+##ifdef F2POLY_SMALL
+#f2poly_t f2poly_t::ext_gcd(f2poly_t & that, f2poly_t & rm, f2poly_t & rn)
+#
+# f2poly_t mprime, nprime, c, q, r, t, qm, qn
+# f2poly_t d # Return value.
+#
+# if *this == 0:
+# rm.bits = 0
+# rn.bits = 1
+# return that
+# if that == 0:
+# rm.bits = 1
+# rn.bits = 0
+# return *this
+#
+# Initialize
+# mprime.bits = 1
+# rn .bits = 1
+# rm .bits = 0
+# nprime.bits = 0
+# c = *this
+# d = that
+#
+# while 1:
+#
+# # Divide
+# # q = c / d, r = c % d
+# c.quot_and_rem(d, q, r)
+# # Note: now c = qd + r and 0 <= r < d
+#
+# # Remainder zero?
+# if r == 0:
+# break
+#
+# # Recycle
+# c = d
+# d = r
+#
+# t = mprime
+# mprime = rm
+# qm = q * rm
+# rm = t - qm
+#
+# t = nprime
+# nprime = rn
+# qn = q * rn
+# rn = t - qn
+#
+# return d
+#
+##endif
+
+# ----------------------------------------------------------------
+##ifndef F2POLY_SMALL
+#f2poly_t f2poly_t::deriv(void)
+#
+# f2poly_t rv = *this
+# rv.demote_1()
+# for (int i = 0; i < rv.num_parts; i++)
+# rv.parts[i] &= 0x55555555
+# rv.trim_parts()
+# return rv
+#
+##endif
+
+# ----------------------------------------------------------------
+# Relies on the fact that f(x^p) = f^p(x) over Fp[x].
+#
+# in = a4 x^4 + a2 x^2 + a0
+# out = a4 x^2 + a2 x + a0
+#
+##ifndef F2POLY_SMALL
+#int f2poly_t::square_root(f2poly_t & rroot)
+#
+# int deg = this->degree()
+# f2poly_t root(0)
+#
+# for (si = 0, di = 0; si <= deg; si+=2, di++):
+# if this->bit_at(si):
+# root.set_bit(di)
+# if this->bit_at(si + 1):
+# return 0
+#
+#
+# rroot = root
+# return 1
+#
+##endif
+
+# ----------------------------------------------------------------
+#int f2poly_t::eval(int c)
+#
+# if c & 1:
+# return this->zcount_one_bits()
+# else
+# return this->parts[0] & 1
136 f2polymod_tm.py
@@ -0,0 +1,136 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2008-11-14
+# ================================================================
+
+import sys
+import re
+import copy
+
+import f2poly_tm
+
+# xxx this is in mid-port from C++.
+
+# ================================================================
+def f2polymod_from_string(string):
+ return f2polymod_t(int(string, 16))
+
+# ================================================================
+class f2polymod_t:
+
+ #def __init__(self, resbits, modbits):
+ # self.modbits = modbits
+ # self.resbits = f2poly_tm.imod(resbits, modbits)
+
+ # Both arguments should be of type f2poly_t.
+ def __init__(self, residue, modulus):
+ self.modulus = modulus
+ self.residue = residue % modulus
+
+ def __add__(a,b):
+ c = f2polymod_t(a.residue + b.residue, a.modulus)
+ return c
+ def __sub__(a,b):
+ c = f2polymod_t(a.residue - b.residue, a.modulus)
+ return c
+ def __mul__(a,b):
+ c = f2polymod_t(a.residue * b.residue, a.modulus)
+ return c
+
+ # xxx fix me
+ def recip(a):
+ pass
+
+#int f2polymod_t::recip(f2polymod_t & rinv)
+# f2poly_t g, a, b;
+# g = this->residue.ext_gcd(this->modulus, a, b);
+#
+# if (g.find_degree() != 0): # Error check
+# //std::cerr << "f2polymod recip: zero or zero divisor.";
+# return 0
+# else:
+# rinv = f2polymod_t(a, this->modulus)
+# return 1
+
+ def __div__(a,b):
+ return a * b.recip()
+
+ # xxx fix me
+ def __pow__(a, e):
+ ap = a.residue
+ one = f2poly_t(1)
+ rv = one
+
+ xxx types
+ if (e == 0):
+ if (a.residue.bits == 0):
+ print >> sys.stderr, "f2polymod_t.exp: 0^0 undefined."
+ sys.exit(1)
+ return one
+ elif (e < 0):
+ if (a.residue.bits == 0):
+ print >> sys.stderr, "f2polymod_t.exp: division by zero."
+ sys.exit(1)
+
+ xxx
+ f2polymod_t inv = one/ *this
+ xp = inv.residue
+ e = -e
+
+ while (e != 0):
+ if e & 1:
+ rv.residue = (rv.residue * xp) % this->modulus
+ e >>= 1
+ xp = (xp * xp) % this->modulus
+ return rv
+
+
+ def __eq__(a,b):
+ return a.bits == b.bits
+ def __ne__(a,b):
+ return not (a == b)
+ def __neg__(a):
+ return a
+
+ def scan(self, string):
+ self.bits = int(string, 16)
+
+ def __str__(self):
+ # xxx temp
+ return self.residue.__str__()
+ #return "%x" % self.bits
+ def __repr__(self):
+ return self.__str__()
+
+
+#std::ostream & operator<<(std::ostream & os, const f2polymod_t & a)
+# a.residue.dprint(os, a.modulus.find_degree() - 1)
+#
+#int f2polymod_t::from_string(char * string, f2poly_t m)
+# f2poly_t r;
+# std::istringstream iss(string, std::ios_base::in);
+# iss >> r;
+# if (iss.fail()) {
+# return 0;
+# }
+# else {
+# *this = f2polymod_t(r, m);
+# return 1;
+# }
+#
+#void f2polymod_t::check_moduli(f2polymod_t & that) const
+# if (this->modulus != that.modulus) {
+# std::cerr
+# << "f2polymod_t: mixed moduli "
+# << this->modulus
+# << ", "
+# << that.modulus
+# << ".";
+# std::cerr << std::endl;
+# exit(1);
+# }
44 f2test
@@ -0,0 +1,44 @@
+#!/usr/bin/python -Wall
+
+from f2poly_tm import *
+import sys
+
+a = f2poly_t(0xff)
+b = f2poly_t(0xf)
+e = 3
+argc = len(sys.argv)
+if (argc == 3):
+ a = f2poly_from_string(sys.argv[1])
+ b = f2poly_from_string(sys.argv[2])
+if (argc == 4):
+ a = f2poly_from_string(sys.argv[1])
+ b = f2poly_from_string(sys.argv[2])
+ e = int(sys.argv[3])
+print "a =", a
+print "b =", b
+
+s = a + b
+print "sum =", s
+
+c = a * b
+print "prod =", c
+
+if (b.bits != 0):
+ q = a / b
+ print "quot =", q
+ r = a % b
+ print "rem =", r
+ print "imod =", f2poly_t(imod(a.bits, b.bits))
+
+print a, "**", e, "=", a**e
+
+g = f2poly_t.gcd(a,b)
+print "gcd =", g
+
+[g, r, s] = f2poly_t.ext_gcd(a, b)
+print "ext_gcd:"
+print " g = ", g
+print " r = ", r
+print " s = ", s
+print " ar + bs = ", a*r + b*s
+
33 fact_m.py
@@ -0,0 +1,33 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+def fact(n):
+ if (n < 0):
+ return 0
+ rv = 1
+ while (n > 0):
+ rv *= n
+ n -= 1
+ return rv
+
+def binc(n, k):
+ if (k > n):
+ return 0
+ if (k < 0):
+ return 0
+ if (k > int(n/2)):
+ k = n - k
+
+ rv = 1
+ for j in range(0, k):
+ rv *= n - j
+ rv /= j + 1
+ return rv
+
122 genquat_tm.py
@@ -0,0 +1,122 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+# Presentation:
+# < a, b | a^2n = 1, b^2 = a^n, ab = ba^-1 >
+#
+# Expressions simplify to a^i b^j for i=0,1,..,n-1 and j=0,1,2,3:
+# * Powers on a don't exceed 2n.
+# * Powers on b don't exceed 4.
+# * Powers on a of n .. 2n-1 may have have a^n replaced with b^2.
+# * The quasi-commutator ab=ba^-1 leads to ba = a^-1b which allows
+# all powers of a, and all powers of b, to be collected together.
+#
+# That is:
+# * ba = a^-1 b
+# * b a^i = a^-i b
+# * b^j a = a^s b^j where s = (-1)^j
+#
+# Thus
+# b^j a^i = b^j-1 b a^i
+# = b^j-2 a^i b^2
+# = b^j-3 a^-i b^3
+# = b^j-4 a^i b^4
+# = ...
+# = a^i b^j if j even
+# = a^-i b^j if j odd
+# = a^si b^j where s = (-1)^j
+#
+# Thus
+# a^i b^j a^k b^l = a^i (b^j a^k) b^l
+# = a^i (a^sk b^j) b^l
+# = a^(i+sk) b^(j+l)
+#
+
+# Inverse of a^i b^j:
+# (a^i b^j)^-1 = b^-j a^-i
+# = b^(4-j) a^(2n-i)
+# = a^s(2n-i) b^(4-j) where s = (-1)^j
+
+import re
+
+class genquat_t:
+ #i = 0
+ #j = 0
+ #n = 0
+
+ def __init__(self, argi, argj, argn):
+ argi %= argn + argn;
+ if (argi >= argn):
+ argj += 2
+ argi -= argn
+ self.n = argn
+ self.i = argi
+ self.j = argj & 3
+
+ def __eq__(a,b):
+ return ((a.i == b.i) and (a.j == b.j))
+
+ def __ne__(a,b):
+ return not (a == b)
+
+ def __mul__(a,b):
+ # a^i b^j a^k b^l = a^(i+sk) b^(j+l)
+ if (a.n != b.n):
+ raise RuntimeError
+ c = genquat_t(0, 0, a.n)
+
+ i = a.i
+ j = a.j
+ k = b.i
+ l = b.j
+ n = a.n
+ twon = n + n
+ if (j & 1):
+ c.i = (i-k+twon) % twon
+ else:
+ c.i = (i+k) % twon
+ c.j = (j+l) & 3
+ if (c.i >= n):
+ c.i -= n
+ c.j += 2
+ c.j &= 3
+ return c
+
+ def inv(a):
+ # Inverse of a^i b^j:
+ # (a^i b^j)^-1 = a^s(2n-i) b^(4-j) where s = (-1)^j
+ if (a.j & 1):
+ msi = a.i
+ else:
+ msi = a.n + a.n - a.i
+ c = genquat_t(msi, -a.j, a.n)
+ return c
+
+ def scan(self, string, argn):
+ groups = re.match(r"^(\d)+,(\d+)$", string).groups();
+ if len(groups) != 2:
+ raise IOError
+ self.__init__(int(groups[0]), int(groups[1]), argn)
+
+ def __str__(self):
+ return str(self.i) + "," + str(self.j)
+
+ def __repr__(self):
+ return self.__str__()
+
+def params_from_string(params_string):
+ n = int(params_string)
+ return n
+
+def from_string(value_string, params_string):
+ n = params_from_string(params_string)
+ obj = genquat_t(0, 0, n)
+ obj.scan(value_string, n)
+ return obj
124 gint_tm.py
@@ -0,0 +1,124 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+import re
+import copy
+
+import sackint
+
+class gint_t:
+
+ def __init__(self, re, im):
+ self.re = re
+ self.im = im
+
+ def __eq__(a,b):
+ if (a.re != b.re):
+ return 0
+ if (a.im != b.im):
+ return 0
+ return 1
+
+ def __ne__(a,b):
+ return not (a == b)
+
+ def __add__(a,b):
+ c = gint_t(a.re + b.re, a.im + b.im)
+ return c
+
+ def __sub__(a,b):
+ c = gint_t(a.re - b.re, a.im - b.im)
+ return c
+
+ def __mul__(a,b):
+ # (ar, ai) * (br, bi)
+ c = gint_t(a.re*b.re - a.im*b.im, a.re*b.im + a.im*b.re)
+ return c
+
+ # Grove's _Algebra_, p. 65
+ # (ar, ai) (ar, ai)(br, -bi) a * conj(b)
+ # -------- = ----------------- = -----------
+ # (br, bi) (br, bi)(br, -bi) norm b
+ #
+ # Then, take the *nearest* integers to the rational coordinates.
+
+ def __div__(a,b):
+ numer = a * b.conj()
+ denom = b.norm()
+ Qre = (1.0 * numer.re) / denom
+ Qim = (1.0 * numer.im) / denom
+ Zre = int(round(Qre))
+ Zim = int(round(Qim))
+ q = gint_t(Zre, Zim)
+ return q
+
+ def __mod__(a,b):
+ q = a / b
+ return a - (q * b)
+
+ def conj(a):
+ return gint_t(a.re, -a.im)
+
+ def norm(a):
+ return a.re*a.re + a.im*a.im
+
+ def scan(self, string):
+ strings = re.split(',', string)
+ n = len(strings)
+ if (n == 1):
+ self.re = int(strings[0])
+ elif (n == 2):
+ self.re = int(strings[0])
+ self.im = int(strings[1])
+ else:
+ raise IOError
+
+ def __str__(self):
+ string = str(self.re) + "," + str(self.im)
+ return string
+
+ def __repr__(self):
+ return self.__str__()
+
+#def from_string(value_string, params_string):
+# if (len(params_string) == 0):
+# print "Modmul requires non-empty parameter string"
+# obj = gint_t([1], [1])
+# obj.scan(value_string, params_string)
+# return obj
+
+#a = gint_t(7,-3)
+#b = gint_t(5,3)
+#sum = a+b
+#diff = a-b
+#prod = a*b
+#q = a/b
+#r = a%b
+#print a, "+", b, "=", sum
+#print a, "-", b, "=", diff
+#print a, "*", b, "=", prod
+#print a, "/", b, "=", q
+#print a, "%", b, "=", r
+#print "qb+r", q*b + r
+
+print
+
+
+a = gint_t(7,-3)
+b = gint_t(5,3)
+
+for i in range(0,10):
+ if (b.norm() == 0):
+ break
+ q = a/b
+ r = a%b
+ print a, b, q, r
+ a = b
+ b = r
65 ispec_gm.py
@@ -0,0 +1,65 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+import ispec_tm
+import ispec_tbl
+import re
+import sys
+
+# I have a *global* for ispec.tbl. This makes it non re-entrant.
+# In particular I won't be able to form, say, the direct product of two
+# different user-specified groups without a redesign.
+
+def get_elements_str(params_string):
+ file_name = params_string
+ matrix = []
+
+ if (file_name == "-"):
+ file_handle = sys.stdin
+ else:
+ try:
+ file_handle = open(file_name, 'r')
+ except:
+ print "Couldn't open \"" + file_name + "\" for read."
+ sys.exit(1)
+
+ lno = 0
+ for line in file_handle:
+ lno += 1
+
+ # Chomp trailing newline, if any.
+ if (line[-1] == '\n'):
+ line = line[0:-1]
+
+ # Strip leading and trailing whitespace.
+ line = re.sub(r"^\s+", r"", line)
+ line = re.sub(r"\s+$", r"", line)
+
+ code_strings = re.split('\s+', line)
+ row = []
+ colno = 0
+ for cs in code_strings:
+ colno += 1
+ try:
+ row.append(int(cs))
+ except:
+ print "Scan error on \"%s\", column %d, line %d, file %s" % (cs,colno,lno,file_name)
+ sys.exit(1)
+ matrix.append(row)
+ if (file_name != "-"):
+ file_handle.close()
+
+ ispec_tm.install_table(matrix)
+
+ n=len(matrix)
+ elts = range(0, n)
+ for i in range(0, n):
+ elts[i] = ispec_tm.ispec_t(i)
+ return elts
12 ispec_tbl.py
@@ -0,0 +1,12 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+ispec_mul_table = [99]
+ispec_inv_table = []
82 ispec_tm.py
@@ -0,0 +1,82 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+import re
+import copy
+import ispec_tbl
+
+import sackgrp
+
+class ispec_t:
+ def __init__(self, argcode):
+ self.code = argcode
+
+ def __mul__(a,b):
+ c = ispec_t(ispec_tbl.ispec_mul_table[a.code][b.code]);
+ return c
+
+ def __eq__(a,b):
+ return (a.code == b.code)
+
+ def __ne__(a,b):
+ return not (a == b)
+
+ def __lt__(a,b):
+ return (a.code < b.code)
+ def __le__(a,b):
+ return (a.code <= b.code)
+ def __gt__(a,b):
+ return (a.code > b.code)
+ def __ge__(a,b):
+ return (a.code >= b.code)
+
+ def inv(a):
+ c = ispec_t(ispec_tbl.ispec_inv_table[a.code]);
+ return c
+
+ def scan(self, string):
+ self.code = int(string)
+
+ def __str__(self):
+ return str(self.code)
+
+ def __repr__(self):
+ return self.__str__()
+
+def params_from_string(params_string):
+ return params_string
+
+def from_string(value_string, params_string):
+ not_used = params_from_string(params_string)
+ k = int(value_string) # xxx needs error checking
+ obj = ispec_t(k)
+ return obj
+
+def install_table(table):
+ ispec_tbl.ispec_mul_table = copy.copy(table)
+ ispec_tbl.ispec_inv_table = []
+ n = len(table)
+
+ # Populate the inv table.
+ # I am being crass here. I'm assuming the Cayley table is good before I start.
+ # The good news is that the is-group functions don't use the inv table.
+ G = []
+ for i in range(0, n):
+ G.append(ispec_t(i))
+ [found, e] = sackgrp.find_id(G)
+ if (found):
+ for i in range(0, n):
+ x = G[i]
+ for j in range(0, n):
+ y = G[j]
+ z = x*y
+ if (z.code == e.code):
+ ispec_tbl.ispec_inv_table.append(j)
+ continue
20 metacyc_gm.py
@@ -0,0 +1,20 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+import metacyc_tm
+
+def get_elements_str(params_string):
+ [p, q, t] = metacyc_tm.params_from_string(params_string)
+ pq = p * q
+ elts = []
+ for i in range(0, p):
+ for j in range(0, q):
+ elts.append(metacyc_tm.metacyc_t(i, j, p, q, t))
+ return elts
183 metacyc_tm.py
@@ -0,0 +1,183 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+import re
+import sackint
+
+# ================================================================
+# Old explanation (circa 2004):
+
+# ----------------------------------------------------------------
+# Multiplication:
+# a^i b^j a^k b^l = a^(i + k t^j) b^(j + l)
+# t != 1 mod p
+# t^q == 1 mod p
+
+# ----------------------------------------------------------------
+# Inversion:
+# (a^i b^j)^(-1) = b^-j a^-i
+# = a^0 b^-j a^-i b^0
+# = a^(0 + -i t^-j) b^(-j + 0)
+# = a^(-i t^-j) b^-j
+
+# ================================================================
+# Alternate point of view, from scratch (2006-11-28):
+# Zm X|_phi Zn (semidirect product):
+# (a, b) + (c, d) = (a + (phi(b))(c), b + d).
+# Zm and Zn are cyclic so the action of b on c is specified by the action of
+# Zn's 1 on Zm's 1. Call this t.
+#
+# ----------------------------------------------------------------
+# An example before I continue further: Let m=7 and n=3. Then we need phi to
+# be a homomorphism from Z3 to Aut(Z7). Here's what Aut(Z7) looks like:
+#
+# Z7 | s1 s2 s3 s4 s5 s6
+# -- + -- -- -- -- -- --
+# 0 | 0 0 0 0 0 0
+# 1 | 1 2 3 4 5 6
+# 2 | 2 4 6 1 3 5
+# 3 | 3 6 2 5 1 4
+# 4 | 4 1 5 2 6 3
+# 5 | 5 3 1 6 4 2
+# 6 | 6 5 4 3 2 1
+#
+# Note that si(x) = ix, i.e. the ith automorphism is just multiplication by i.
+# Also, how do we compose automorphisms? si(sj(x)) = ij(x) so si o sj is sij.
+# So, arithmetic on the i's and j's is done in the multiplicative group of Z7.
+#
+# Now, Aut(Z7) is isomorphic to Z6, but how? Additive groups of Zm always are
+# cyclic of order m with 1 as generator; multiplicative groups of Zp* are
+# always cyclic of order p-1, but with a generator we usually have to search
+# for. By searching we can find that 3 (or 5) generates Z7*. So, Aut(Z7) is
+# cyclic with automorphism s3 (or s5) as generator. Here are the powers of 3
+# mod 7:
+# 3^1 3^2 3^3 3^4 3^5 3^6
+# 3 2 6 4 5 1.
+# So the cyclic structure of the cyclic group Aut(Z7) is
+# s3 s2 s6 s4 s5 s1
+# with s3 as generator. (If s5 is used as the generator, then the cycle
+# structure is the reverse of this.)
+#
+# So, back to the semidirect product of Z7 and Z3, the possible homomorphisms
+# from the order-3 cyclic group Z3 to the order-3 cyclic group Z7 are specified
+# by the image of Z3's 1. It can map to s1 (trivial homomorphism), s2
+# (monomomorphism), or s4 (monomomorphism):
+#
+# Z3 | phi_1 phi_2 phi_3
+# -- + ----- ----- -----
+# 0 | s1 s1 s1
+# 1 | s1 s2 s4
+# 2 | s1 s4 s2
+#
+# Since Z3 is cyclic, and since Aut(Z7) is cyclic, to specify phi we need only
+# to specify the image of Z3's 1. Call that st.
+#
+# Let c be in Z7 and b in Z3. What is (phi(b))(c)? Since phi is a
+# homomorphism and Z3 is cyclic, written additively, phi(b) = b*phi(1). Now,
+# phi(1) is some automorphism st of Z7. Moreover, it can't be any old
+# automorphism: the order of st must divide the order of Z3's 1. So, st^n must
+# be the identity automorphism s1. Since the arithmetic in Aut(Z7) is that of
+# the multiplicative group Z7*, this means that t^n must be 1 mod m.
+# ----------------------------------------------------------------
+
+
+
+# ================================================================
+# Auxiliary function:
+# Second component of return value is t.
+# First compoment of return value is a flag indicating whether t was found.
+def find_t(p, q):
+ for t in range(2, p):
+ if (sackint.intmodexp(t, q, p) == 1):
+ return [1, t]
+ return [0, 0]
+
+# ================================================================
+class metacyc_t:
+
+ def __init__(self, i, j, p, q, t):
+
+ tq = sackint.intmodexp(t, q, p)
+ if ((tq % p) != 1):
+ print "metacyc: t^q must be 1 mod p"
+ print "Got p =", p, "q =", q, "t =", t
+ raise RuntimeError
+
+ # xxx jrk 2006-11-28 allow trivial homomorphisms.
+ #if ((t % p) == 1):
+ # print "metacyc: t must not be 1 mod p"
+ # print "Got p =", p, "q =", q, "t =", t
+ # raise RuntimeError
+
+ self.i = i % p
+ self.j = j % q
+ self.p = p
+ self.q = q
+ self.t = t
+
+ def __eq__(a,b):
+ return ((a.i == b.i) and (a.j == b.j))
+
+ def __ne__(a,b):
+ return not (a == b)
+
+ def __mul__(a,b):
+ if ((a.p != b.p) or (a.q != b.q) or (a.t != b.t)):
+ print "Parameter mismatch in metacyc mul"
+ raise RuntimeError
+ ci = (a.i + b.i * sackint.intmodexp(a.t, a.j, a.p)) % a.p
+ cj = (a.j + b.j) % a.q
+ c = metacyc_t(ci, cj, a.p, a.q, a.t)
+ return c
+
+ def inv(a):
+ ci = -a.i * sackint.intmodexp(a.t, -a.j, a.p)
+ cj = -a.j
+ c = metacyc_t(ci, cj, a.p, a.q, a.t)
+ return c
+
+ def scan(self, string, argp, argq, argt):
+ groups = re.match(r"^(\d)+,(\d+)$", string).groups();
+ if len(groups) != 2:
+ raise IOError
+ self.__init__(int(groups[0]), int(groups[1]), argp, argq, argt)
+
+ def __str__(self):
+ return str(self.i) + "," + str(self.j)
+
+ def __repr__(self):
+ return self.__str__()
+
+def params_from_string(params_string):
+ pqt = re.split(',', params_string)
+
+ if (len(pqt) == 3):
+ p = int(pqt[0])
+ q = int(pqt[1])
+ t = int(pqt[2])
+ elif (len(pqt) == 2):
+ p = int(pqt[0])
+ q = int(pqt[1])
+ [got_it, t] = find_t(p, q)
+ if (not got_it):
+ print "metacyc_t: No t found for p =", p, "q =", q
+ print "Got: ", params_string
+ raise IOError
+ else:
+ print "metacyc_tm.from_string: expected parameters p,q or p,q,t."
+ print "Got: ", params_string
+ raise IOError
+ return [p, q, t]
+
+def from_string(value_string, params_string):
+ [p, q, t] = params_from_string(params_string)
+ obj = metacyc_t(0, 0, p, q, t)
+ obj.scan(value_string, p, q, t)
+ return obj
211 mod_tm.py
@@ -0,0 +1,211 @@
+#!/usr/bin/python -Wall
+
+# ================================================================
+# This software is released under the terms of the GNU GPL.
+# Please see LICENSE.txt in the same directory as this file.
+# John Kerl
+# kerl.john.r@gmail.com
+# 2007-05-31
+# ================================================================
+
+import sys
+import re
+import copy
+
+class mod_t:
+ def __init__(self, resarray, modarray):
+ self.check_lengths(len(resarray), len(modarray), "residues", "moduli")
+ self.check_moduli(modarray)
+ self.residues = copy.copy(resarray)
+ self.moduli = copy.copy(modarray)
+ for i in range(0, len(modarray)):