class quad_module
with __init__( self, matrix_of_relations, Gram_matrix)
class quad_module_element
with __init__( self, quad_module, coefficients_of_lin_comb)
quad_module.gens[i]
, __add__
and relatives,
class quad_module_subgroup
with __init( self, list_of_gens)
quad_module.subgroup( list_of_gens), __add__, dual
All three classes are implemented. The main methods are functional.
When a quad_module is created the matrix of relations $M$ is replaced by the matrix $D$ of its elementary divisors: $$ D = RMS \qquad (R,S \in \text{GL}(n,{\mathbb Z}) $$ The (given) generators are supposed to satisfy the relations given by $D$. Accordingly, the given Gram matrix $G$ is replaced by $G[R^{-1}]$.
Subgroups of the underlying quadratic module ${\mathbb Z}^n/M{\mathbb Z}^n$ are in one to one correspondence to lattices $M{\mathbb Z}^n \subseteq L \subseteq {\mathbb Z}^n$ (here $n$ denotes the size of $M$). We can write $L=N{\mathbb Z}^n$ fo a suitable regular $n\times n$ matrix $N$, which is unique up to right multiplication by unimodular matrices. Hence we may assume that $N$ is in (say, lower) Hermite normal form (HNF), which makes it unique. Note that $N^{-1}M$ is integral.
Thus subgroups are represented internally by (lower) HNF matrices left dividing $M$. At initialisation time this unique matrix is computed from the given list of generators for the subgroup to be created.
Using SAGE internal functions and a reasonable design for our classe the matrix manipulations are reduced to a minimum. This ensures a as much as possible separation of logical structure from actual data representation for the sake of easy extensibility and maintenance of our code.
__radd__
does not work correctly
qfmodule( number_field_element)
class chi_invariant
and, say, the method quad_module.chi_invariant()