The C interface of the mmgroup project
Introduction
This document describes the functionality of the C modules in this project. For most of these C modules there is also a python extension. Unless otherwise stated, each documented C function is wrapped by a Cython function with the same name and signature.
Note that almost all parameters of such a C function are declared as
(signed or unsigend) integers, or as pointers to such integers. In
python, a numpy
array of appropriate dtype
may be passed as
an argument to a parameter delared as a pointer to an integer.
Description of the mmgroup.mat24
extension
The automatically generated file mat24_functions.c
contains the C
code for the functions exported by the python extension mmgroup.mat24
.
These functions are documented in file mat24_functions.c
. Here
just give an overview of the functionality of that module.
File mat24_functions.c
has been generated from the source file
mat24_functions.ske
using the code generator in module
mmgroup.generate_c
.
The functions in file mat24_functions.c
perform basic computations
in the Golay code, in its cocode, and in the Mathieu group Mat24
.
They also deal with Parker loop Pl
and with its automorphism group
AutPl
. A more comfortable python interface to these objects is
provided by the python classes GCode
, Cocode
, PLoop
, and
AutPL
in module mmgroup
.
All C functions in file mat24_functions.c
start with the prefix
mat24_
. These functions are also called from C functions in other
modules. Therefore we store the binary code for these functions in
a shared library. For some of these functions there are also
macros (defined with #define
), starting with mat24_def_
.
There is a one-to-one correspondence between the functions in
mat24_functions.c
and the function exported from the python
extension mmgroup.mat24
, see subsection
Mapping C functions to python functions for details.
The python class Mat24
in module mmgroup.dev.mat24.mat24_ref
contains pure python implementations of most functions of the
mmgroup.mat24
extension as class methods. This class is used for
testing and as a substitute for the mmgroup.mat24
extension in
an early stage of the build process.
In the following subsections the term C functions refers to the
C functions in file mat24_functions.c
. In the documentation, the
names of the C functions are given without the mat24_
prefix.
The term API reference means the main document
The mmgroup API reference of this project.
The Golay code C
and its cocode C*
The Mathieu group Mat24
operates as a permutation group on a set
of 24 elements which we label with numbers 0,…,23 for use in Python
and C. So it also operates on a vector space V = GF(2)**24
, with
GF(2) = {0,1}
. Here **
means exponentiation.
A vector v
in a vector space over GF(2)
is called a bit
vector. We represent a bit vector as an integer, so that the
i
-th bit of v
(with valence 2**i
) is the i
-th
component of v
.
The Golay code C
ia a 12-dimensional subspace of V
fixed by
Mat24
. There are functions for checking and completing codewords
and for getting the syndrome of a 24-bit vector.
We internally use a basis of V
such that the first 12 basis
vectors are a transversal of the Golay cocode and the last 12 basis
vectors span the Golay code. These basis vectors are listed in the
API reference.
We represent vectors in V
, C
and C*
and in the subset of
octads of C
as follows:
The 759 octads are numbered from 0 to 758. They do not form a vector space. The 2**12 Golay code words are represented as binary numbers 0 to 4095. The 2**12 cocode words are represented as binary numbers 0 to 4095. A more detailed description is given in the API reference.
As usual, binary numbers representing bit vectors are added with the
XOR operation ^
. Unused high bits in input bit vectors are ignored.
Functions changing an object from one representation xxx
to another
representation yyy
are named xxx_to_yyy
, where xxx
,
yyy
is as follows:
vect: standard representation of a bit vector in V = GF(2)**24
coded as a 24-bit integer.
vintern: internal representation a bit vector in V as a vector in
the basis given above, coded as 24-bit integer.
gcode: representation of a Golay code word in the basis given
given above, coded as 12-bit integer.
octad: representation as an octad numbered from 0 to 758
(in lexical order given by representation 'gcode')
cocode: representation as a cocode word in the basis given above,
coded as 12-bit integer.
All these representations are given as unsigned integers.
We implement the following conversion functions:
vect_to_vintern, vintern_to_vect, vect_to_cocode,
vintern_to_vect, gcode_to_vect, cocode_to_vect.
Here irrelevant bits of the input are ignored. Function
cocode_to_vect
returns one of many possible solutions.
In the following functions the input is checked and the function fails in case of an error:
vect_to_gcode, vect_to_octad, gcode_to_octad,
octad_to_vect, octad_to_gcode
In case of failure, these C functions return a special value as
indicated in the documentation of the function in the .c file.
The corresponding python functions raise ValueError
in case
of failure.
Function syndrome()
takes a vector v
and calculates its
syndrome, which is a vector of minimum weight equivalent to v
modulo the Golay code. Function cocode_syndrome()
takes a
cocode
representation of a cocode word instead.
Function scalar_prod()
returns the scalar product of a Golay code
vector in gcode
and a cocode vector in cocode
representation.
The Mathieu group Mat24
This class also contains support for the Mathieu group Mat24
.
An element of Mat24
can be represented in one of the following ways:
perm: Representation as an array of length 24 encoding a
permutation of the integers 0,...,23 as a mapping.
m24num: Representation as an integer 0 <= i < 244823040. Here i
is the number of the permutation in lexicographic order.
So the identity permutation is coded as 0.
matrix: Representation as a 12 x 12 bit matrix acting on the Golay
code by right multiplication. This matrix acts on a Golay
code vectors (given in the 'gcode' representation) by
right multiplication.
Such a matrix is implemented as an array of integers with
each integer corresponding to a row vector of the matrix.
The purpose of this representation is to support
the Parker loop and its automorphism group. Therefore a
row vector is implemented as a 32-bit integer.
We implement the following conversion functions:
m24num_to_perm, perm_to_m24num, perm_to_matrix, matrix_to_perm.
There is a function perm_check()
for checking if an array of
length 24 really represents an element of the Mathieu group Mat24
.
All other function operating on Mat24
in any way do not check if
their inputs are really in Mat24
. They will output garbage on bad
input, but they are not supposed to crash.
The easiest way to create a random element of Mat24
is to create
a random integer 0 <= x < 244823040
, and to call function
m24num_to_perm(x)
.
Operation of the group Mat24
on vectors
Elements of Mat24
operate from the right on vectors
in V = GF(2)**24
or on Golay code or cocode vectors.
A function performing such an operation has the name:
op_<vector>_<group>
where <vector>
indicates the representation of the vector space
and <group>
indicates the representation of the group. We
implement the functions:
op_vect_perm, op_gcode_matrix, op_gcode_perm, op_cocode_perm.
E.g. function op_gcode_matrix
operates on a Golay code word (in
gcode
representation) by right multiplying an element m
of Mat24
with it. Here element m
is a 12 times 12 matrix
(in matrix
representation).
Group operation in the group Mat24
Multiplication and inversion in the group Mat24
is supported for
the permutation representation perm
. Therefore we have functions:
mul_perm, inv_perm
The Parker loop Pl
We support the Parker loop Pl
and also its automorphism group
AutPl
.
An element of Pl
is a pair (v, s)
, with v
a Golay code
word and s
a sign bit, as described in the API reference. We
represent the element (v, s)
as a 13-bit integer, with v
given by bits 0,…,11 (in gcode
representation) and the sign
s
given by bit 12. We call this representation of the Parker
loop the ploop
representation. So we can convert and element
of C
in ‘gcode’ representation to an element of Pl
in
ploop
representation by adjusting the sign in bit 12.
Function mul_ploop()
returns the product of two elements of
the Parker Loop. Function inv_ploop()
returns the inverse of
ab element of the Parker loop.
Let theta
be the cocycle for the Parker loop defined in the
API reference. For an element v1
of of C
or Pl
in
gcode
or ploop
representation, the function
ploop_theta(v1)
returns the value theta(v1)
(which is
in C*
) in cocode
representation. Function
ploop_cocode(v1, v2)
returns the value of the coycle
theta(v1, v2)
, which is 0 or 1.
The group AutPl
of standard automorphisms of the Parker loop
An automorphism of the Parker loop is implemented as an array a
of twelve 32-bit integers. The lowest 13 bits of a[i]
encode
the image of the i-th basis vector of the Parker loop. Here the
basis of the Parker loop corresponds to the selected basis of the
Golay code, and each basis vector has positive sign.
The bits 13,...,24
of the vectors a[i]
encode a quadratic
form which facilitates computations in AutPl
, as described
in section Implementing Automorphisms of the Parker loop in the
Guide for developers.
This representation of AutPl
is called the autpl
representation. We only use the autpl
representation for
elements of AutPl
.
Function perm_to_autpl(c, p)
computes an automorphism m
of the Parker loop created from an element p
of Mat24
(given in perm
representation) and a cocode element c
(given in cocode
representation). If m
is equal to
the result of perm_to_autpl(c, p)
, then we can get back
p
and c
be computing p = autpl_to_perm(m)
and
c = autpl_to_cocode(m)
.
Function cocode_to_autpl(c)
is equivalent to function
perm_to_autpl(c, p0)
, where p0
is the identity
permutation. Note that:
perm_to_autpl(c, p) = cocode_to_autpl(c) * perm_to_autpl(0, p).
Here perm_to_autpl(0, p)
is equivalent to
standard representative of p
in AutPl
, and
cocode_to_autpl(c)
is a diagonal automorphism, as described
in section Automorphisms of the Parker loop of the
API reference.
Function op_ploop_autpl(v, m)
applies Parker loop automorphism
m
to element v
of Pl
and returns the result.
Function mul_autpl(m1, m2)
computes the product m1 * m2
of
the Parker loop automorphisms m1
and m2
. Function
inv_autpl(m1)
computes the inverse of the Parker loop
automorphism m1
.
Auxiliary functions
Here is an overview of some auxiliary functions in this class. They are described in the corresponding function documentation::
bw24 bit weight of the lowest 24 bits of an integer
lsbit24 min(24, least significant bit pos.) for an integer
gcode_weight weight of a Golay code word in 'gtype' representation
vect_to_bit_list given a bit vector in V, it computes the lists of
the positions of the 0 bits and of the 1 bits of v.
extract_b24 extract bits from bit vector using a 24-bit mask
spread_b24 spread bit vector according to a 24-bit mask
Internal operation
For switching from the standard representation to the internal
representation we use three tables with 2**8
entries of 24
bit
length. For switching back from internal to standard representation
we use three other tables of the same format. There are also tables
for computing the syndrome of a vector in V
with respect to the
Golay code. There is yet another table for the cocycle theta
of
the Parker loop.
Abbreviations for functions and parameters in this class
The following list of abbreviations used in names of functions allows to infer the action of most functions in this module:
Abbreviation Meaning Data type
assoc associator (in Golay code or Parker loop)
autpl automorphism of the Parker loop Pl uint32_t[12]
bw24 bit weight of the lowest 24 bits of an int
cap intersection (of Golay code elements)
cocode element of Golay cocode C* uint32_t
cocycle cocycle: Pl times Pl -> {0,1}
comm commutator (in Golay code or Pl)
gcode element of Golay code C uint32_t
inv inversion (in Mat24, Pl, or AutPl)
lsbit24 least significant bit of an integer,
counting bits 0,...,23 only
m24num number of an element of Mat24 uint32_t
matrix element of Mat24 as binary matrix
acting on the Golay code C uint32_t[12]
mul multiplication (in Mat24, Pl, or AutPl)
net Benes network for an element of Mat24 uint32_t[9]
octad number of an octad, i.e. a Golay code
element of weight 8 uint32_t
op op_<vector>_<operation> means:
apply <operation> to <vector>
op_all apply operation to all vectors
perm element of Mat24 as a permutation uint8_t[24]
ploop element of the Parker loop Pl uint32_t
pow power operator (in Pl)
scalar_prod scalar product (of Golay code and cocode)
suboctad suboctad, see function suboctad_to_cocode
syndrome syndrome (after decoding Golay code) uint32_t
theta cocycle theta: Pl -> C^* in Parker loop
to <x>_to_<y> means: return representation <y>
of an object given in representation <x>
vect vector in V = GF(2)**24 uint32_t
vintern vector in V, in internal representation uint32_t
Conventions for parameters in C functions
Parameters of functions are either integers or arrays of integers.
Here all integer types are unsigned and of fixed length, such as
uint8_t
, uint16_t
or uint32_t
.
The type of a parameter is given by a single letter in the name of the parameter:
Name Meaning Type
a array specified in documentation of function unspecified
c Golay cocode element, represented as 'cocode' uint32_t
m permutation in Mat24 or automorphism of Pl
represented as a bit matrix uint32_t[12]
p permutation in Mat24 represented as 'perm' uint8_t[24]
u_<x> unsigned integer, e.g. unspecified
u_exp: integer denoting an exponent
u_m24: number of a permutation in Mat24
u_octad: number of octad, 0 < u_octad < 259
u_width: integer denoting a bit width
v vector in V, Golay code C or Parker loop Pl
represented as vect, vintern, gcode or ploop uint32_t
Integer input parameters have name u_<x>
, e.g. u_m24, u_exp
.
An integer computed by a function is returned as return value.
Input array parameters have a digit as a suffix, e.g.: v1, v2, m1
.
Output array parameters have the suffix _out
, e.g.: p_out
.
Input/output array parameters have the suffix _io
, e.g.: m_io
.
Mapping C functions to python functions
All C functions in module mat24_functions
are documented.
This documentation is not repeated for the corresponding python
functions in module mmgroup.mat24
.
The rules for converting a C function to a python function are as follows:
To obtain the name of the python function, strip off the prefix
mat24_
from the name of a C functions.To obtain the tuple of input parameters for the python function, take the tuple of parameters of the C function and drop are parameters with suffix
_out
.In the corresponding python function, an iterable object may be passed where the C function expects a pointer to an integer. The minimum length of that iterable object is either clear from the context or documented in the C function.
To obtain the return value of the python function, check if the C function has any parameters with suffix
_out
. Then the sequence of returned objects is the sequence of these parameters, possibly preceded by the return value if the C function returns an integer value.As usual in python, a sequence of length 1 is returned as a single object, and a sequence of length >= 1 is returned as a tuple.
A parameter with suffix
_out
is returned as a list of integers.A C function may fail under certain circumstances.
A failure of a function is indicated in the return value of the function. Details are given in the documentation of the function. The corresponding python function raises ValueError if the C function fails.
The python function drops the return value of the C function from the sequence of returned python objects in certain cases.
If the documentation of the C function contains the phrase ‘Returns 0 in case of success and (anything else) in case of failure’ then the return value is just a status indicator and hence dropped by the python function.
If the documentation of the C function contains a phrase like ‘Returns the length of the list
xxx_out
’ then the python function adjusts the length of that returned list appropriately and drops the return value.Parameters with suffix
_io
refer to pointers in the C function and hence to iterables in the corresponding python function. Here the sufix_io
means that the function may modify that iterable object.
C interface
Header files
File mat24_functions.h
is the header file for mat24_functions.c
.
Defines
-
MAT24_ORDER
Order of Mathieu group
Mat24
. This is equal to 244823040.
-
mat24_def_lsbit24(v1)
Macro version of function
mat24_lsbit24
.
-
mat24_def_lsbit24_pwr2(v1)
Special macro version of function
mat24_lsbit24
.This is faster than
mat24_def_lsbit24
, but herev1
must be power of two.
-
mat24_def_parity12(v1)
Parity of vector
v1
of 12 bits length.Generate a sequence of statements that replaces
v1
by the bit parity ofv1 & 0xfff
.
-
mat24_def_octad_to_gcode(o)
Eqivalent to
mat24_def_octad_to_gcode(o)
mat24_def_octad_to_gcode(o)
returns the number of the Golay code word corresponding to octado
. Parametero
is not checked.
-
mat24_def_gcode_to_octad(v)
Eqivalent to
mat24_def_gcode_to_octad(v)
mat24_def_gcode_to_octad(v)
returns the number of the octad corresponding to Golay code vectorv
, withv
ingcode
. It returns garbage ifv
is not an octad.
-
mat24_def_not_nonstrict_octad(v)
Check if
v
(or its complement) is an octad.Returns 0 if
v
(or its complement) is an octad and 1 otherwise.Vector
v
must be given ingcode
representation
-
mat24_def_gcode_to_vect(v)
Convert Golay code element number
v
to a vector inGF(2)^24
Macro version of function
mat24_gcode_to_vect
.
-
mat24_def_syndrome_from_table(t)
Convert entry
t
of tableMAT24_SYNDROME_TABLE
to syndrome.An entry
t
of the tableMAT24_SYNDROME_TABLE
encodes an odd cocode syndrome. The macro returns that syndrome as a bit vector.
Enums
-
enum mat24_rand_flags
Flags describing subgroups of the Mathieu group \(M_{24}\).
This enumeration contains flags describing some subgroups of the Mathieu group \(M_{24}\) fixing certain subsets (or sets of subsets) of the set \(\tilde{\Omega} = \{0,\ldots,23\}\) on which the group \(M_{24}\) acts. Intersetions of these subgroups may be described by combining these flags with the bitwise or operator
|
. For each flag we state the set being fixed.Values:
-
enumerator MAT24_RAND_2
fixes \(\{2, 3\} \)
-
enumerator MAT24_RAND_o
fixes \(\{0, \ldots,7 \}\)
-
enumerator MAT24_RAND_t
fixes \(\{\{8i,\ldots,8i+7\} \mid i < 3 \}\)
-
enumerator MAT24_RAND_s
fixes \(\{\{4i,\ldots,4i+3\} \mid i < 6 \}\)
-
enumerator MAT24_RAND_l
fixes \(\{\{2i, 2i+1\} \mid 4 \leq i < 12 \}\)
-
enumerator MAT24_RAND_3
fixes \(\{1, 2, 3\} \)
-
enumerator MAT24_RAND_2
C functions for the Mathieu group \(M_{24}\)
File mat24_functions.c
contains the C implementation of the functionality of Python module mmgroup.mat24
This covers the Golay code, its cocode, the Parker loop, the Mathieu group Mat24, and the group of standard automorphisms of the Parker loop.
Functions
-
uint32_t mat24_lsbit24(uint32_t v1)
Return position of least significant bit of an integer.
The function returns the minimum of the number 24 and the position of the least significant bit of
v1
. It uses a De Bruijn sequence.
-
uint32_t mat24_bw24(uint32_t v1)
Returns the bit weight of the lowest 24 bits of
v1
.
-
uint32_t mat24_vect_to_bit_list(uint32_t v1, uint8_t *a_out)
Stores the positions of 1-bits of a bit vector to an array.
Let
w
be the bit weight of the bit vectorv1 & 0xffffff
, i.e. number of bits ofv1
at positions< 24
equal to one. Then the ordered bit positions where the corresponding bit ofv1
is 1 are stored ina_out[0],...,a_out[w-1]
.Then
(v1 & 0xffffff)
has24 - w
zero bits. The ordered list of the positions of these zero bits is stored ina_out[w],...,a_out[23]
.The function returns the bit weight
w
.
-
uint32_t mat24_vect_to_list(uint32_t v1, uint32_t u_len, uint8_t *a_out)
Stores the positions of 1-bits of a bit vector to an array.
Let
w
be the minimum of the inputu_len
and the bit weight of the bit vectorv1 & 0xffffff
, i.e. number of bits ofv1
at positions< 24
equal to one. Then the firstw
bit positions where the corresponding bit ofv1
is 1 are stored ina_out[0],...,a_out[w-1]
in natural order. The function returnsw
.For small values
w
this function is faster than functionmat24_vect_to_bit_list
.
-
uint32_t mat24_extract_b24(uint32_t v1, uint32_t u_mask)
Extract the bits of 24-bit vector
v1
given by the masku_mask
If
u_mask
has bits equal to one at positionsi_0, i_1, ..., i_k
(in ascending order) then the bit ofv1
at positioni_j
is copied to the bit at positionj
of the return value forj = 0,...,k
.
-
uint32_t mat24_spread_b24(uint32_t v1, uint32_t u_mask)
Spread bits of 24-bit vector
v1
according to the masku_mask
If
u_mask
has bits equal to one at positionsi_0, i_1, ..., i_k
(in ascending order) then the bit ofv1
at positionj
is copied to the bit at positioni_j
of the return value forj = 0,...,k
.
-
uint32_t mat24_vect_to_vintern(uint32_t v1)
Convert bit vector
v1
inGF(2)^24
fromvector
tovintern
representation.
-
uint32_t mat24_vintern_to_vect(uint32_t v1)
Convert bit vector
v1
inGF(2)^24
fromvintern
tovector
representation.
-
uint32_t mat24_vect_to_cocode(uint32_t v1)
Return Golay cocode element corresponding to a bit vector in
GF(2)^24
.This amounts to reducing the vector
v1
(given invector
representation) modulo the Golay code. The function returns the cocode element corresponding tov1
incocode
representation.
-
uint32_t mat24_gcode_to_vect(uint32_t v1)
Convert Golay code element number
v1
to a vector inGF(2)^24
Input
v1
is a Golay code element ingcode
representation. The function returns the bit vector corresponding tov1
invector
representation.
-
uint32_t mat24_cocode_to_vect(uint32_t c1)
Return a vector in
GF(2)^24
corresponding to cocode element.Here
c1
is the number of a cocode element incocode
representation. One of2**12
possible preimages ofc1
inGF(2)^24
is returned invector
representation.
-
uint32_t mat24_vect_to_gcode(uint32_t v1)
Return a vector in
GF(2)^24
as a Golay code element.If the vector
v1
(given invector
representation) is in the Golay code then the function returns the number of that Golay code word. Thus the return value is ingcode
representation.If
v1
is not in the Golay code then the function returns(uint32_t)(-1)
.
-
uint32_t mat24_gcode_to_octad(uint32_t v1, uint32_t u_strict)
Return a Golay code vector as an octad.
If
u_strict
is even then the function acts as follows:If the Golay code vector
v1
(given ingcode
representation) is an octad or a complement of an octad then the function returns the number of that octad. Thus the return value is inoctad
representation. Then we have0 <= octad(v1, strict) < 759
.If
v1
is not a (possibly complemented) octad then the function returns(uint32_t)(-1)
.If
u_strict
is odd then the function returns(uint32_t)(-1)
also in case of a complemented octadv1
.
-
uint32_t mat24_vect_to_octad(uint32_t v1, uint32_t u_strict)
Return a vector in
GF(2)^24
as an octad.If
u_strict
is even then the function acts as follows:If the vector
v1
(given invector
representation) is an octad or a complement of an octad then the function returns the number of that octad. Thus the return value is inoctad
representation. Then we have0 <= octad(v1, strict) < 759
.If
v1
is not a (possibly complemented) octad then the function returns(uint32_t)(-1)
.If
u_strict
is odd then the function returns(uint32_t)(-1)
also in case of a complemented octadv1
.
-
uint32_t mat24_octad_to_gcode(uint32_t u_octad)
Convert an octad to a Golay code vector.
Given an octad
u_octad
(inoctad
representation), the function returns the number of the corresponding Golay code number ingcode
representation.There are 759 octads. The function returns
(uint32_t)(-1)
in caseu_octad >= 759
.
-
uint32_t mat24_octad_to_vect(uint32_t u_octad)
Convert an octad to a bit vector in
GF(2)^24
.Given an octad
u_octad
(inoctad
representation), the function returns bit vector corresponding to that octad invector
representation.There are 759 octads. The function returns
(uint32_t)(-1)
in caseu_octad >= 759
.
-
uint32_t mat24_cocode_syndrome(uint32_t c1, uint32_t u_tetrad)
Return Golay code syndrome of cocode element
c1
.Here
c1
is a cocode element incocode
representation. mat24_cocode_syndrome(c1, u_tetrad) is equivalent to mat24_syndrome(mat24_cocode_to_vect(c1), u_tetrad).The function returns a Golay code syndrome as described in the documentation of function mat24_syndrome().
-
uint32_t mat24_syndrome(uint32_t v1, uint32_t u_tetrad)
Return Golay code syndrome of word
v1
.Here
v1
is an arbitrary word inGF(2)**24
invector
representation. The function returns a Golay code syndrome ofv1
(of minimum possible bit weight) as a bit vector invector
representation.Such a syndrome is unique if it has weight less than 4. In that case the unique syndrome is returned.
If the minimum weight of the syndrome is four then the six possible syndroms form a partition of the the underlying set of 24 elements. In this case we return the syndrome of bit weight four where the bit at position
u_tetrad
is set. Therefore parameteru_tetrad
must satisfy0 <= u_tetrad <= 24
; otherwise the function fails.If the minimum weight of the sydrome is at most three, parameter
u_tetrad
must satisfy0 <= u_tetrad < 24
; otherwise the function fails.The function returns
(uint32_t)(-1)
in case of failure.
-
uint32_t mat24_gcode_weight(uint32_t v1)
Returns bit weight of Golay code word
v1
divided by 4.Here
0 <= v1 < 4096
is the number of a Golay code word, i.e.v1
is given ingcode
representation.
-
uint32_t mat24_gcode_to_bit_list(uint32_t v1, uint8_t *a_out)
Store bit positions of Golay code
v1
in arraya_out
Here
0 <= v1 < 4096
is the number of a Golay code word, i.e.v1
is given ingcode
representation. The Golay code wordv1
is stored in the array referred bya_out
as an ordered list of the positions of the bits being set in the wordv1
.That array must have physical length at least 24. The function returns the actual length of the returned array, which is equal to the bit weight of the word
v1
.
-
uint32_t mat24_cocode_weight(uint32_t c1)
Return the minimum possible weight of the cocode vector
c1
Here
c1
is a cocode element incocode
representation.
-
uint32_t mat24_cocode_to_bit_list(uint32_t c1, uint32_t u_tetrad, uint8_t *a_out)
Store Golay code syndrome of cocode word
c1
in an array.Here
c1
is an cocode word in cocode representation. The function stores the sorted bit positions of the syndrome ofc1
in the array referred bya_out
and returns the actual length of that array, which is the weight of the syndrome. The array referred bya_out
must have physical length at least 4.Such a syndrome is unique if it has weight less than 4. In that case the unique syndrome is returned.
If the minimum weight of the syndrome is four then the six possible syndroms form a partition of the the underlying set of 24 elements. In this case we return the syndrome of bit weight four where the bit at position
u_tetrad
is set. Therefore parameteru_tetrad
must satisfy0 <= u_tetrad < 24
; otherwise the function fails.If the minimum weight of the sydrome is at most three, parameter
u_tetrad
must satisfy0 <= u_tetrad <= 24
; otherwise the function fails.The function returns
(uint32_t)(-1)
in case of failure.
-
uint32_t mat24_cocode_to_sextet(uint32_t c1, uint8_t *a_out)
Store a cocode word
c1
in arraya_out
as a sextet.Here
c1
is an cocode word in cocode representation. That cocode word must correspond to a syndrome of length four, i.e. the syndrome must be a tetrad. Otherwise the function fails.The function stores the six tetrads that make up the sextet
c1
ina_out[4*i],...,a_out[4*i+3]
fori = 0,...,5
. The (ordered) tetrads are stored in lexical order.The function returns
(uint32_t)(-1)
ifc1
has not minimum weight 4.
-
uint32_t mat24_scalar_prod(uint32_t v1, uint32_t c1)
Return scalar product of Golay code and cocode vector.
v1
is a Golay code vector in ‘gcode’ representation,c1
is a cocode vector in cocode representation.Actually the function returns the bit parity of
v1 & c1 & 0xfff
.
-
uint32_t mat24_suboctad_to_cocode(uint32_t u_sub, uint32_t v1)
Convert even suboctad of octad to cocode representation.
The function converts a suboctad
u_sub
(insuboctad
representation) of an octadv1
(ingcode
representation) to a cocode element. It returns that cocode element incocode
representation.Each octad
v1
has 64 even subsets, when each subset ofv1
is identified with its complement inv1
. These subsets are called suboctads. Letb_0, ..., b_7
be the elements of the octadv1
in natural order. Then the even subset(b_0 , b_i)
has suboctad number2**(i-1)
fori = 1,...,6
. Combining suboctads by symmetric difference corresponds to combining their numbers byxor
. The empty subocatad has number zero. This yields a one-to-one correspondence between the integers0,...,63
and the suboctads of a fixed octadv1
, when identifying a suboctad with its complement.The function returns the suboctad of
v1
with numberu_sub
incocode
representation. Octadv1
must be given ingcode
representation. Ifv1
is a complement of an octado
theo
is taken instead ofv1
.The function fails if
v1
does not represent an octad. It returns(uint32_t)(-1)
in case of failure.
-
uint32_t mat24_cocode_to_suboctad(uint32_t c1, uint32_t v1)
Convert cocode element
c1
to suboctad of octadv1
The function converts a cocode element
c1
(incocode
representation) of an octadv1
(ingcode
representation) to a suboctad.This is an inverse of function mat24_suboctad_to_cocode(). The function returns the suboctad number corresponding to the cocode element
c1
, ifv1
is an octad andc1
is an even subset ofv1
. See documentation of function mat24_suboctad_to_cocode() for the numbering of the suboctads.The function fails if
v1
is not a octad orc1
cannot be represented as an even subset ofv1
. Ifv1
is a complement of an octado
theo
is taken instead ofv1
. The function returns(uint32_t)(-1)
in case of failure.
-
uint32_t mat24_suboctad_weight(uint32_t u_sub)
Return parity of halved bit weight of the even suboctad.
Here parameter
u_sub
is the number of a suboctad. A suboctad cooresponds to a subset of an octad of even parity. The function returns 0 is the bit weight of that subset is divisible by four and 1 otherwise.The numbering of suboctads is described in the documentation of function mat24_suboctad_to_cocode().
-
uint32_t mat24_suboctad_scalar_prod(uint32_t u_sub1, uint32_t u_sub2)
Return scalar product of two suboctads.
The function returns the scalar product of the two suboctads with the numbers
u_sub1, u_sub2
.Here the scalar product is the parity of the vector
u_sub1 & u_sub2
whenu_sub1
andu_sub2
are given as subsets of an octad in vector notation.But in this functions parameters
u_sub1, u_sub2
are suboctad numbers as documented in function mat24_suboctad_to_cocode().
-
uint32_t mat24_cocode_as_subdodecad(uint32_t c1, uint32_t v1, uint32_t u_single)
Represent a cocode element as a subset of a docecad.
Given a Golay cocode element
c1
(incocode
representation) and a dodecadv1
(ingcode
representation), the function returns a bit vectorc_out
equivalent to the cocode wordc1
, which is a subset of the dodecadd1
. This is possible if the scalar product ofc1
and the complement ofv1
is even. Otherwise the function fails.The user may specify a bit position
0 <= u_single < 24
disjoint from the bits of dodecadd1
. Then that bit of the return valuec_out
will be set if the scalar product mentioned above is odd, and the function succeeds also in this case.The intersection of
c_out
withv1
has bit weight at most 6. If that bit weight is equal to 6 thenc_out
contains the least significant bit of the bit vector corresponding tov1
.The function fails if
v1
is not a dodecad. It returns(uint32_t)(-1)
in case of failure.
-
uint32_t mat24_ploop_theta(uint32_t v1)
Returns the theta function for the Parker loop.
Here function
theta()
is a quadratic function from the Golay codeC
to the cocodeC*
. Parameterv1
of functiontheta
is a Golay code word ingcode
representation. The result of thetheta
function is returned as a Golay cocode word incocode
representation.The cocycle of the Parker loop is given by:
cocycle(v1, v2) = mat24_scalar_prod(theta(v1), v2),
where mat24_scalar_prod() computes the scalar product.
The function evluates the lower 12 bits of
v1
only. Thusv1
may also be an element of the Parker loop.
-
uint32_t mat24_ploop_cocycle(uint32_t v1, uint32_t v2)
Returns the cocycle of the Parker loop.
Here parameters
v1
andv2
are Golay code vectors ingcode
representations or elements of the Parker loop, coded as in functionmat24_mul_ploop
. Then the Parker loop product ofv1
andv2
is given byv1 (*) v2 = v1 ^ v2 * (-1)**cocycle(v1, v2).
-
uint32_t mat24_mul_ploop(uint32_t v1, uint32_t v2)
Returns the product of two elements of the Parker loop.
Here the Parker loop elements
v1
andv2
are integers coded as follows:bit 0,...,11: a Golay code word in ``gcode`` representation bit 12: Parker loop sign
The other bis of
v1
andv2
are ignored.
-
uint32_t mat24_pow_ploop(uint32_t v1, uint32_t u_exp)
Returns a power of an element of the Parker loop.
Here
v1
is a the Parker loop element coded as in function mat24_mul_ploop().u_exp
is the exponent. The function returns the powerv1 ** exp
as an element of the Parker loop.E.g. mat24_pow_ploop(v1, 3) is the inverse of
v1
.
-
uint32_t mat24_ploop_comm(uint32_t v1, uint32_t v2)
Return commutator of Golay code words
v1
andv2
This is equal to 0 if the intersection of the bit vectors
v1
andv2
has bit weight 0 mod 4, and equal to 1 is that intersection has bit weight 2 mod 4. Wordsv1
andv2
must be given ingcode
representation.For Parker loop elements
v1
andv2
(coded as in functionmat24_mul_ploop
) the commutator ofv1
andv2
is equal to(-1) ** mat24_ploop_comm(v1, v2),
where
**
denotes exponentiation.
-
uint32_t mat24_ploop_cap(uint32_t v1, uint32_t v2)
Return intersection of two Golay code words as cocode word.
Here
v1
andv2
are Golay code words ingcode
representation. The result is a cocode word returned incocode
representation.
-
uint32_t mat24_ploop_assoc(uint32_t v1, uint32_t v2, uint32_t v3)
Return associator of Golay code words
v1, v2,
andv3
This is the parity of the intersection of the bit vectors
v1, v2,
andv3
. So the function returns 0 or 1. Vectorsv1, v2, v3
are ingcode
representation.The associator of three Parker loop elements
v1, v2, v3
is equal to(-1) ** mat24_ploop_assoc(v1, v2, v3) .
Here
v1, v2, v3
are encoded as in function mat24_mul_ploop().
-
uint32_t mat24_ploop_solve(uint32_t *p_io, uint32_t u_len)
Return cocode element that kills signs of Parker loop elements.
Here
p_io
refers to an array ofu_len
Parker loop elements are coded as in function mat24_mul_ploop(). The function tries to find a cocode element that makes all these Parker loop elements positive, when operating on them as a diagonal automorphism. The function returns the least cocode element in lexical order satisfying that condition in the bits0,...,11
of the return value. For that order we assume that lower bits have higher valence. If no such cocode element exists, the function fails.We set bit 12 of the return value to indicate a failure.
The array
p_io
is destroyed. More specifically, the firstk
entries of that array are changed to an array of linear independent Parker loop elements. When thesek
elements are mapped to positive Parker loop elements, this also yields a solution of the original problem. If the problem cannot be solved then we putp_io[k-1] = 0x1000
.The function returns the value
k
in bits31,...,16
of the result.
-
uint32_t mat24_perm_complete_heptad(uint8_t *p_io)
Complete permutation in the Mathieu group
Mat24
from 7 images.This is an auxilary function for function mat24_perm_from_heptads(). We use the terminology introduced in that function.
The function completes the array
p_io
to a permutationp
in the Mathieu groupMat24
. On output, permutationp
is given as a mappingi -> p_io[i]
fori = 0,...,23
.On input, the images
p_io[i]
must be given fori = 0,1,2,3,4,5,8
; the other entries ofp_io
are ignored.The set
(p_io[i], i = 0,1,2,3,4,5,8)
must be an umbral heptad with distiguished elementp_io[8]
. Then the mappingi -> p_io[i], i = 0,1,2,3,4,5,8
is a feasible mapping between umbral heptads; it extends to a unique permutation inMat24
. Note that8
is the distingished element of the umbral heptad(0,1,2,3,4,5,8)
.The function returns 0 if the mapping given on input can be extended to an element of
Mat24
, and a nonzero value otherwise.Implementation idea:
We choose pentads, i.e. subsets of size 5 of the set
(0,....,23)
that consist of known valuesp_io[i]
. We calculate the syndromes of such pentads, which are triads, i.e. sets of size three. Calculating the syndromes of the preimages of these pentads we obtain mappings between triads. Intersecting triads in a suitable way we obtain mappings between singletons, and hence peviously unknown images of elements of the set(0,....,23)
.
-
uint32_t mat24_perm_check(uint8_t *p1)
Check if permutation is in in the Mathieu group
Mat24
.The function checks the mapping
i -> p1[i]
,i = 0,...,23
.It returns zero if that mapping is a permutation in
Mat24
and a nonzero value otherwise.The implementation uses function mat24_perm_complete_heptad().
-
uint32_t mat24_perm_complete_octad(uint8_t *p_io)
Complete an octad given by 6 elements of it.
Given entries
p_io[i], i = 0,1,2,3,4,5
, we calculate valuesp_io[6], p_io[7]
such that the set(p_io[i], 0 <= i < 8)
is an octad. Furthermore, we order the valuesp_io[6], p_io[7]
in such way that the mappingi -> p_io[i]
may be extended to a permutation in the grpupMat24
. This restrtiction determines the order uniquely. Note that the set0,...,7
is an octad, which is called the standard octad.The set
p_io[i], i = 0,1,2,3,4,5
must be a subset of an octad; otherwise the function fails. The function returns 0 in case of success and(uint32_t)(-1)
in case of failure.The implementation is a simplified version of function mat24_perm_complete_heptad().
-
uint32_t mat24_perm_from_heptads(uint8_t *h1, uint8_t *h2, uint8_t *p_out)
Complete a mapping to a permutation in the Mathieu group
Mat24
A permutation in the Mathieu group
Mat24
is a mapping from the set(0,...,23)
to itself. The function completes the mappingh1[i] -> h2[i]
,0 <= i < 7
,0 <= h1[i], h2[i] < 24
to a permutationi -> p_out[i]
,0 <= i < 24
in the groupMat24
. The result is returned in the arrayp_out[i]
.The sets
h1[i], 0 <= i < 7
andh2[i], 0 <= i < 7
must be umbral heptads, and the mapping fromh1
toh2
must be feasible.An umbral heptad is a set of seven elements of the set
(0,...,23)
which is not a subset of an octad. The syndrome of an umbral heptad, i.e. the smallest set equivalent to the heptad modulo the Golay code, is a singleton containing exactly one element of the umbral heptad. That element is called the distiguished element of the heptad. A feasible mapping from an umbral heptad to another umbral heptad is a mapping that maps the distiguished element of the first heptad to the distiguished element of the second heptad.It can be shown that a feasible mapping from an umbral heptad to another umbral heptad extends to a unique element of the Mathieu group.
The function returns 0 if the mapping
h1[i] -> h2[i]
can be extended to an element ofMat24
and(uint32_t)(-1)
otherwise.The implementation uses function mat24_perm_complete_heptad().
-
uint32_t mat24_perm_from_map(uint8_t *h1, uint8_t *h2, uint32_t n, uint8_t *p_out)
Complete a mapping to a permutation in the Mathieu group
Mat24
A permutation in the Mathieu group
Mat24
is a mapping from the set(0,...,23)
to itself. The function tries to complete the mappingh1[i] -> h2[i]
,0 <= i < n
,0 <= h1[i], h2[i] < 24
to a permutationi -> p_out[i]
,0 <= i < 24
in the Mathieu groupMat24
. In case of success, such a permutation is stored in the arrayp_out
.The function returns
-1 if the mapping
h1[i] -> h2[i]
does not extend to a legal permutation of the numbers 0,…,23. Note that duplicate entries inh1
orh2
are illegal.0 if no such permutation exists in the Mathieu group
Mat24
.1 if the mapping
h1[i] -> h2[i]
extends to a unique permutation inMat24
.2 if if the mapping
h1[i] -> h2[i]
can be completed to several permutations inMat24
, and not all entriesh1[i]
can be covered by an octad. This may happen in casen = 6
only.3 if if the mapping
h1[i] -> h2[i]
can be completed to several permutations inMat24
, and all entriesh1[i]
can be covered by an octad.If the return value is greater then zero then a suitable permutation in
Mat24
is returned in the array referred byp_out
. The function computes the lowest permutation (in lexical order) that mapsh1
to `h2
.Caution:
Some input mappings allow several output permutations. Changing the specification of this function such that the same input leads to a different output permutation destroys the interoperability between different versions of the project!!
-
uint32_t mat24_m24num_to_perm(uint32_t u_m24, uint8_t *p_out)
Compute permutation in the Mathieu group
Mat24
from its number.The Mathieu group has order
244823040
. We assign numbers0 <= n < 244823040
to the elements ofMat24
, in lexicographic order, with0
the number of the neutral element. This is just a convenient way to refer to an element ofMat24
.The function calculates the permutation with the number
u_m24
and stores it in the arrayp_out
as a mappingi -> p_out[i]
.0 <= u_m24 < 244823040
must hold; otherwise the function fails.The function returns 0 in case of success and
(uint32_t)(-1)
in case of failure.
-
uint32_t mat24_perm_to_m24num(uint8_t *p1)
Compute number of a permutation in the Mathieu group
Mat24
This is the inverse of function mat24_m24num_to_perm().
Given a permutation
i -> p1[i], 0 <= i < 24
, the function returns the numbern
of that permutation. We have0 <= n < 244823040
, as described in functionmat24_m24num_to_perm
.The function returns garbage if
p1
is not a valid permutation inMat24
. One may use function mat24_perm_check() to check if permutationp1
is inMat24
.
-
void mat24_perm_to_matrix(uint8_t *p1, uint32_t *m_out)
Convert permutation in the Mathieu group
Mat24
to bit matrix.The input of the function is the permutation
p: i -> p1[i]
,0 <= i < 24
which must be in the Mathieu groupMat24
.The function computes a
12 times 12
bit matrixm
, acting on a Golay code vectorv
(ingcode
representation) by right multiplication. Then we havev * m = p(v)
. Bitm[i,j]
is stored in bitj
of the the integerm_out[i]
.Output
m_out[i], 0 <= i < 12
contains garbage ifp
is not inMat24
.Implementation idea:
In the standard basis of
GF(2)**24
, that operation corresponds to a permutation. We have precomputed a matrix converting that standard basis to an internal basis, where Golay code words are visible, and also the inverse of that matrix. Thus the operation is just an (optimized) sequence of matrix multiplications.
-
void mat24_matrix_to_perm(uint32_t *m1, uint8_t *p_out)
Convert bit matrix to permutation in the Mathieu group
Mat24
This is the inverse of function mat24_perm_to_matrix()
The input
m1
of the function is a bit matrix that maps a Golay code wordv
top(v) = v * m1
, as described in function mat24_perm_to_matrix().The function computes the permutation
p: i -> p_out[i]
,0 <= i < 24
, from that matrix and stores the result in the output vectorp_out
of length 24.Output
p_out[i], 0 <= i < 24
contains garbage ifm1
is not bit matrix corresponding to an element ofmat24
.Implementation idea:
We could have reversed the operation of function mat24_perm_to_matrix(), but the following implememtation is faster:
Converting rows of matrix
m1
fromgcode
tostandard
representation yields the images of some Golay code words as bit vectors. Intersecting these bit vectors in a suitable way yields the images of singletons and hence the requestend permutation.
-
void mat24_matrix_from_mod_omega(uint32_t *m1)
Complete bit matrix for Mathieu group
Mat24
from submatrix.Let the input
m1
of the function be a 12 times 12 bit matrix that maps a Golay code wordv
top(v) = v * m1
, as described in functionmat24_perm_to_matrix()
.There are cases where the first 11 rows and columns of
m1
can be deduced from an external source, but the last row and column is unknown. This means the operation of an element ofMat24
on the Golay code is know modulo the code wordOmega = (1,...,1)
only. This function completes such an 11 times 11 bit matrix to a 12 times 12 matrix in place.
-
static uint32_t dodecad_to_heptad(uint8_t *d1, uint8_t *h_out)
Compute a (unique) heptad from a dodecad.
This is a (rather technical) auxiliary function for function
mat24_perm_from_dodecads
Let
d1
be a dodecad as in function mat24_perm_from_dodecads().There is a unique umbral heptad
h
, as defined in the documentation of function mat24_perm_from_heptads(), satisfying the properties described below.The function evaluates the first 9 elements
d1[i], 0 <= i < 9
. It fails if these elements are not a subset of a dodecad or not pairwise disjoint.The function returns 0 in case of success and
(uint32_t)(-1)
in case of failure.Properties of heptad
h
:h
containsd1[i]
for0 <= i < 5
and also the unique elementh_5
in the intersection ofd1
and the syndromeS5
of the set(d1[i], 0 <= i < 5)
.Let
S5 = (h_5, h_6, h_7)
such thatMat24
contains a mapping that mapsi
tod1[i]
fori < 5
andi
toh_i
fori = 5, 6, 7
. This determinesh_6
uniquely. Thenh_6
is not in the dodecadd1
. LetT
be the tetrad containing the set(d1[0], d1[1], d1[2], h_6)
. TetradT
contains exactly one setU
intersectingd1
in 3 elements disjoint to(d1[i], 0 <= i < 5)
. Then heptadh
contains the elementd_7
of the singletonU \ d1
as ts distinguished element.The function puts
h_out[i] = d1[i]
for0 <= i < 5
andh_out[5] = h_5, h_out[6] = d_7.
-
uint32_t mat24_perm_from_dodecads(uint8_t *d1, uint8_t *d2, uint8_t *p_out)
Find permutation in
Mat24
mapping one dodecad to another.A dodecad is a word of the Golay code of weight 12. Given two dodecads
d1, d2
, and five elementsd1[0],...,d1[4]
ofd1
, and also five elementsd2[0],...,d2[4]
ofd2
, there is a unique permutationp
inMat24
with the following properties:d1 is mapped to d2 , d1[i] is mapped to d2[i] for 0 <= i < 5 .
On input the function takes two dodecads
d1, d2
as arrays of integers, and it computes a permutationp: i -> p_out[i]
satisfying the properies given above. In case of success it storesp
in the arrayp_out
. Only the first 9 elementsd1[i], d2[i], 0 <= i < 9
ofd1
andd2
are evalutated. There is at most one dodecad containingd1[i], 0 <= i < 9
and at most one dodecad containingd2[i], 0 <= i < 9
, assumingd1[i] != d1[j]
andd2[i] != d2[j]
fori != j
.The function fails if the evaluated entries of
d1
or ofd2
are not a subset of a dodecad or not pairwise disjoint.The function returns 0 in case of success and
(uint32_t)(-1)
in case of failure.The implementation calls function dodecad_to_heptad() for contructing (unique) heptads
h1
andh2
fromd1
andd2
. Then it calls function mat24_perm_from_heptads() for computing the unique permutation inMat24
that mapsh1
toh2
.
-
uint32_t mat24_op_vect_perm(uint32_t v1, uint8_t *p1)
Apply a permutation in the Mathieu group
Mat24
to a bit vector.Apply the permutation
p: i -> p1[i]
to the bit vectorv1
. This maps biti
ofv1
to bitp1[i]
of the returned result.
-
uint32_t mat24_op_gcode_matrix(uint32_t v1, uint32_t *m1)
Apply a
12 times 12
bit matrix to a Golay code vector.A matrix
12 times 12
bit matrixm
must be encoded in the input parameterm1
as specified in function mat24_perm_to_matrix(). The function returns the matrix productv1 * m
as bit vector. Inputv1
and the return value are Golay code words given ingcode
representation.
-
uint32_t mat24_op_gcode_perm(uint32_t v1, uint8_t *p1)
Apply a permutation in the group
Mat24
to a Golay code vector.Apply the permutation
p: i -> p1[i]
(which must be an element of the Mathieu group Mat24) to the Golay code wordv1
, withv1
given ingcode
representation.The function returnes the permuted Golay code word in
gcode
representation.
-
uint32_t mat24_op_cocode_perm(uint32_t c1, uint8_t *p1)
Apply a permutation in the group
Mat24
to a Golay cocode element.Apply the permutation
p: i -> p1[i]
(which must be an element of the Mathieu group Mat24) to the Golay cocode elementc1
, withc1
given incocode
representation.The function returnes the permuted cocode word in
cocode
representation.
-
void mat24_mul_perm(uint8_t *p1, uint8_t *p2, uint8_t *p_out)
Compute product of two permutations in the Mathieu group
Mat24
Here inputs
p1, p2
must be permutations represented as mappingsi -> p1[i], i -> p2[i]
. The function computes the productp1 * p2
and stores it in the arrayp_out
in the same form. Thusp_out[i] = p2[p1[i]]
.Input errors are not detected, but output buffer overflow is prevented. Any overlap between
p1, p2,
andp_out
is possible.
-
void mat24_inv_perm(uint8_t *p1, uint8_t *p_out)
Compute the inverse of a permutation in the Mathieu group
Mat24
Here input
p1
must be a permutation represented as mappingi -> p1[i]
. The function computes the inverse ofp1
and stores it in the arrayp_out
in the same form. Thusp_out[p1[i]] = i
.Input errors are not detected, but output buffer overflow is prevented. Any overlap between
p1
andp_out
is possible.
-
void mat24_autpl_set_qform(uint32_t *m_io)
Auxiliary function for function mat24_perm_to_autpl()
Given a Parker loop autmorphism
a
, the function computes a quadratic formqf
on the Golay code defined as follows:qf(g[i]) = 0
for all basis vectorsg[i]
of the standard basis of the Golay code. Furthermore we haveqf(v1 + v2) = qf(v1) + qf(v2) + b(v1, v2) ,
where
b
is a bilinear form on the Golay code defined byb(x,y) = theta(p(x), p(y)) + theta(x, y) (mod 2).
Here
p
is the element of the groupMat24
obtained by taking the automorphisma
modulo sign, andtheta
is the cocycle of the Parker loop. Thenb
is an alternating bilinear form by [Seys20], Lemma 4.1.Let
b[i,j] = b(g[i], g[j])
whereg[i]
is thei-th
basis vector of the Golay code in our selected standard basis.Input
m_io
represents the Parker loop automorphisma
as documented in function mat24_perm_to_autpl(). Here we modify the arraym_io
by storing the bitb[i,j]
in bit13+j
of entrym_io[i]
fori > j
.So the quadratic form
qf
is now also stored in the arraym_io
representing the automorphsma
. As explained in [Seys20] this facilitates computation in the automorphism group of the Parker loop.
-
void mat24_perm_to_autpl(uint32_t c1, uint8_t *p1, uint32_t *m_out)
Construct a Parker loop automorphism.
The function combines a cocode element
c1
and a permutationp
in the Mathieu groupMat24
to a Parker loop automorphism. Herec1
must be given incocode
representation. Permutationp
must be given as a mappingi -> p1[i], 0 <= i < 24
.Up to sign, the image of an element of the Parker loop is the corresponding Golay code vector permuted by the permutation
p
. The sign of the image of thei
-th positive basis vector of the Parker loop is given by biti
ofc1
. This determines the automorphism uniqely. We will writeAutPL(c1, p)
for that automorphism.The function returns the automorphism
AutPL(c1, p)
as an arraym_out
of 12 integers of typeuint32_t
. The lowest 13 bits ofm_out[i]
contain the image of thei
-th positive basis vector. Here each image is encoded as a Parker loop element as in functionmat24_mul_ploop
.We also compute a quadratic form in the higher bits of the entries
of
m_out
, as described in function mat24_autpl_set_qform(). This facilitates computations in the automorphism group of the Parker loop.Let
Id
be the neutral element inMat24
. Then we haveAutPL(c1, p) = AutPL(c1, Id) * AutPL(0, p) .
-
void mat24_cocode_to_autpl(uint32_t c1, uint32_t *m_out)
Compute a diagonal Parker loop automorphism.
The function converts a cocode element
c1
to a Parker loop automorphism. Herec1
must be given incocode
representation. Such an automorphism is called a diagnonal asutomorphism; it changes the signs of the Parker loop elements only.The resulting automorphism is stored in
m_out
in the same way as in function mat24_cocode_to_autpl().If
p0
is an array representing the neutral element of the groupMat24
thenmat24_cocode_to_autpl(cl, m_out)
is equivalent tomat24_perm_to_autpl(c1, p0, m_out)
.
-
void mat24_autpl_to_perm(uint32_t *m1, uint8_t *p_out)
Extract permutation from Parker loop automorphism.
Ignoring the signs of the Parker loop, an automorphism
m1
of the Parker loop is an automorphism of the Golay code and can be represented as a permutation in the Mathieu groupMat24
. Herem1
must be encoded as described in function mat24_perm_to_autpl().The function computes the permutation in the group
Mat24
corresponding the automorphismm1
and returns it inp1
as a mappingi -> p1[i]
.
-
uint32_t mat24_autpl_to_cocode(uint32_t *m1)
Extract cocode element from Parker loop automorphism.
Given an automorphism
m1
of the Parker loop, as constructed by function mat24_perm_to_autpl(), the function returns a cocode elementc
incocode
representation. Elementc
has the following property:Let
p
be the permutation inMat24
obtained fromm1
by calling mat24_autpl_to_perm(m1, p). Then callingmat24_perm_to_autpl(c, p, m2)
, wherem2
is a suitable array, constructs a copym2
ofm1
fromc
andp
.
-
uint32_t mat24_op_ploop_autpl(uint32_t v1, uint32_t *m1)
Apply a Parker loop automorphism to a Parker Loop element.
Apply Parker loop automorphism
m1
to Parker Loop elementv1
and return the result as a Parker Loop element.Here
m1
is a Parker loop autmorphism as constructed by function mat24_perm_to_autpl().v1
and the return value is an element of the Parker loop, encoded as in function mat24_mul_ploop().
-
void mat24_mul_autpl(uint32_t *m1, uint32_t *m2, uint32_t *m_out)
Compute the product of two Parker Loop automorphisms.
Given two Parker Loop automorphism
m1, m2
the function computesm1 * m2
and stores the result inm_out
. All Parker loop automorphisms are encoded as in function mat24_perm_to_autpl().For an element
a
of the Parker loop we havem_out(a) = m2(m1(a))
.
-
void mat24_inv_autpl(uint32_t *m1, uint32_t *m_out)
Compute the inverse of a Parker Loop automorphisms.
Given a Parker Loop automorphism
m1
the function computes the inverse ofm1
and stores the result inm_out
. All Parker loop automorphisms are encoded as in function mat24_perm_to_autpl().
-
void mat24_perm_to_iautpl(uint32_t c1, uint8_t *p1, uint8_t *p_out, uint32_t *m_out)
Compute inverse Parker Loop automorphism from permutation.
This is equivalent to
mat24_inv_perm(p1, p_out); mat24_perm_to_autpl(c1, p1, m_temp); mat24_inv_autpl(m_temp, m_out);
The function saves some intermedate steps so that it is faster.
-
void mat24_perm_to_net(uint8_t *p1, uint32_t *a_out)
Compute modified Benes network for permutation of 24 entries.
The Benes network is computed for the permutation
p: i -> p1[i]
. The network consists of 9 layers. The returned arraya_out
of length 9 describes that network. In layeri
, entryj
is to be exchanged with entryj + d[i]
, if bitj
of the valuea_out[i]
is set. Hered[i] = 1,2,4,8,16,8,4,2,1
fori = 0,...,8
. For all such exchange steps we havej & d[i] == 0
. We also assert that no entry with index>=24
will be touched.
-
void mat24_op_all_autpl(uint32_t *m1, uint16_t *a_out)
Auxiliary function for computing in the monster.
The function is used for applying the automorphism
m1
of the Parker loop to a vector of the196884
-dimensional representation of the monster.m1
is encoded as in function mat24_perm_to_autpl().It computes a table
a_out[i], i = 0,...,0x7ff
, such that(a_out[i] & 0x7ff)
is the imagem1(i)
of the Parker loop elementi
modulo the center of the Parker loop. Signs are stored in bits12,...,14
ofa_out[i]
as follows:Bit 12: (sign of m1(i)) ^ (odd & P(i)) Bit 13: (sign of m1(i)) Bit 14: (sign of m1(i)) ^ (bit 11 of m1(i))
Here
odd
is the parity of the automorphism, andP()
is the power map of the Parker loop.
-
void mat24_op_all_cocode(uint32_t c1, uint8_t *a_out)
Auxiliary function for computing in the monster.
This is a simplified version of function mat24_op_all_autpl(), which is used for applying the diagonal automorphism
c1
of the Parker loop (encoded incocode
representation) to a vector of a representation of the monster.The function computes a table
a_out[i], i= 0,...,0x7ff
, containing the signs related to this operation as follows:Bit 0: (sign of c1(i)) ^ (odd & P(i)) Bit 1: (sign of c1(i)) Bit 2: same as bit 1
Here
odd
andP()
are as in function mat24_op_all_autpl().
Variables
-
const uint16_t MAT24_OCT_DEC_TABLE[759]
Table for converting
octad
togcode
representation.The public macro
mat24_def_octad_to_gcode
uses this table
-
const uint8_t MAT24_OCT_ENC_TABLE[2048]
Table for converting
gcode
tooctad
representation.The public macro
mat24_def_gcode_to_octad
uses this table
-
const uint16_t MAT24_THETA_TABLE[]
Table containing data about the Golay code.
For
0 <= d < 0x800
entryd
contains the following information the code wordd
, withd
ingcode
representation.Bit 11,…,0:
mat24_ploop_theta(d)
Bit 14,…,12: Bit weight of code word
d
inGF(2)**24
divided by 4Bit 15: reserved
We have
d**2 = (-1)**<Bit 12 of entry d>
ford
in the Parker loop.
C functions for generating random elements of \(M_{24}\)
File mat24_random.c
contains the C implementations of the functions for generation random elements of some subgroups of the Mathieu group \(M_{24}\).
Equivalent python function are coded in module mmgroup.tests.test_mat24.test_mat24_rand
.
A subgroup of \(M_{24}\) is decribed by an integer of type uint_32_t
encoding a bit mask. Each bit in that mask encodes a certain subgroup of \(M_{24}\). By combining several bits with bitwise pr we may evcode the intersection of the subgroups corresponding to the bits being set.
The mapping of the bits to the subgroups is given in the description of the enum
type mat24_rand_flags
in file mat24_functions.h
.
Functions
-
uint32_t mat24_complete_rand_mode(uint32_t u_mode)
Complete an intersection of subgroups of \(M_{24}\).
Here the integer
u_mode
is a combination of flags of typeenum mat24_rand_flags
describing an intersection \(H\) of subgroups of \(M_{24}\). Then the group \(H\) may be contained in more subgroups of \(M_{24}\) encoded as bits of an integer of typeenum mat24_rand_flags
. This function sets all bits inu_mode
corresponding to groups containing \(H\). Furthermore, the function clears all unused bits in parameteru_mode
.The function returns the modified parameter
u_mode
.
-
int32_t mat24_perm_in_local(uint8_t *p1)
Compute some subgroups containing an element of \(M_{24}\).
Let \(p_1\) be a permutation in \(M_{24}\) given as an array of 24 integers. The function computes a set of subgroups of \(M_{24}\) containing \(p_1\). These computations are done for all subgroups corresponding to the flags defined in
enum mat24_rand_flags
. The function returns an integermode
that is the combination of flags of typeenum mat24_rand_flags
describing the subgroups of \(M_{24}\) containing \(H\) .The function returns -1 if \(p_1\) is not in \(M_{24}\).
-
int32_t mat24_perm_rand_local(uint32_t u_mode, uint32_t u_rand, uint8_t *p_out)
Generate a random element of a subgroup of \(M_{24}\).
The function generates an element of a subgroup \(H\) of the Mathieu group \(M_{24}\). Here the parameter
u_mode
is a combination of flags of typeenum mat24_rand_flags
describing the group \(H\) as an intersection of subgroups of \(M_{24}\). The generated permutation is stored in the arrayp_out
of length 24.Parameter
u_rand
is an integer describing the element of subgroup \(H\) to be generated. Hereu_rand
is reduced modulo the order of \(H\). In order to generate a uniform random element of \(H\), the user should generate a uniform random number0 <= u_rand < MAT24_ORDER
, whereMAT24_ORDER
is the order of the group \(M_{24}\).The function returns 0 in case of success and -1 in case of failure.
-
int32_t mat24_m24num_rand_local(uint32_t u_mode, uint32_t u_rand)
Generate number of random element of a subgroup of \(M_{24}\).
The function generates an element of a subgroup \(H\) of the Mathieu group \(M_{24}\). Here the parameters
u_mode
and andu_rand
are as in functionmat24_perm_rand_local
.The function returns the number of the generated element of \(M_{24}\) in case of success and -1 in case of failure.
See function
mat24_m24num_to_perm
for the numbering of the elements of \(M_{24}\).
-
int32_t mat24_m24num_rand_adjust_xy(uint32_t u_mode, uint32_t v)
Make an element of the Parker loop compatible with a subgroup.
Here parameter
v
is an element \(d\) of the Parker loop encoded as in filemat24.c
. Parameteru_mode
describes a subgroup of the Mathieu group \(M_{24}\) as in functionmat24_perm_rand_local
.Eventually, we want to construct random elements in a larger group then \(M_{24}\). For some values of
u_mode
we want to use additional generators corresponding to a subloop of the Parker loop. Here the details are dictated by the 2-local structure of the Monster.If
u_mode
is set so that one or more Golay cocode vectors of weight 2 are fixed pointwise then we require the scalar product of \(d\) with all these fixed weight-2 vectors to be zero. The function modifies the Parker loop element \(d\) appropriately and returns the modified element.
Generating C code for the mmgroup.mat24
extension
In this section we give a brief overview over the modules in
mmgroup.dev.mat24
used for generating C code for the
mmgroup.mat24
extension.
Module mat24_ref
Module mat24_ref
contains the class Mat24.
Class Mat24
in module mmgroup.dev.mat24.mat24_ref
is the
table-providing class used by the code generator to generate the C
file mat24_functions.c
. That C file contains the functionality
of the python extension mmgroup.mat24
.
Class Mat24
may also be used as a table-providing class for
generating other C files.
Class Mat24
also exports the same functions as the mmgroup.mat24
extension as class methods. So it can be used for testing that extension
and also as a pure-python substitute for that extension.
Class Mat24
is based on class mat24tables.Mat24Tables
. It also
uses classes, functions and tables from the following modules
in mmgroup.dev.mat24
:
make_addition_table
,make_mul_transp
,mat24aux
,mat24heptad
,mat24theta
Module mat24tables
Module mat24tables
contains the class Mat24Tables
Class Mat24Tables
is a base for class Mat24
in module
mmgroup.dev.mat24.mat24_ref
. It contains the basis of the Golay code
and of (a set of representatives of) the Golay cocode. It also contains
tables for fast conversion of a vector in V = GF(2)**24
from the
standard to the internal representation and vice versa. That class also
contains a table of the syndromes of all 2048
odd elements of the
cocode. The 759
octads, i.e. Golay code word of length 8
are
numbered from 0
to 758
. Class Mat24Tables
provides tables
for computing the number of a octad from a Golay code word representing
an octad and vice versa.
Class Mat24Tables
also contains python versions of some C functions
in file mat24_functions.c
using these tables.
Module mat24aux
The module contains classes Lsbit24Function
and MatrixToPerm
.
Class Lsbit24Function
contains tables and directives for computing
the least significant bit of a 24-bit
integer using a
DeBruijn sequence. This may be overkill for such a simple function,
but it may also be considered as a didactic example of a
table-providing class.
Class MatrixToPerm
contains a directive that generates highly
optimized code for converting a bit matrix acting on a Golay code
word to a permutation in the Mathieu group Mat_24
. Here we
assume the bit matrix actually encodes an element of the
Mathieu group; otherwise garbage is returned. The Golay code
word must be given as an integer in gcode
representation.
Module mat24heptad
Support for completing a permutation in the Mathieu group
A heptad is s subset of seven elements of the set on which that
Mathieu group acts. Under certain circumstances a mapping from one
heptad to another heptad can be completed to a unique element of
mat_24
. The C function mat24_perm_from_heptads
in file
mat24_functions.c
performs that task. It calls a simpler
function mat24_perm_complete_heptad
in that file which
completes a mapping from a fixed heptad to variable heptad.
This file contains python implementations of functions
mat24_perm_complete_heptad
and mat24_perm_from_heptads
.
The C function mat24_perm_to_m24num
maps the elements of the
Mathieu group Mat_24
to the set if integers
0, ..., order(Mat_24)
. Function mat24_perm_complete_heptad
is also used as a subroutine of function mat24_m24num_to_perm
which compute the inverse of that mapping. This module also
contains python implementations of these functions.
Class HeptadCompleter
is a table-providing class that is used
for code generation. It also exports the functionality of this
module.
Function hint_for_complete_heptads
prints an explanation
of the implementation of function mat24_perm_complete_heptad
,
including some precalulated data required for that implementation.
Function test_complete_octad
test the correcteness of function
mat24_perm_complete_heptad
. Here it suffices to check that
the identity permutation is generated correctly from the required
input values, and that the intersections of (possibly complemented)
octads and syndromes are indeed singletons if the ought to be
singletons.
Module make_addition_table
The module contains class BitMatrixMulFix
.
Class BitMatrixMulFix
contains a directive that generates
code to multiply a fixed bit matrix with a variable bit matrix.
The C function mat24_perm_to_matrix
uses this kind of matrix
multiplication to convert a permutation in the Mathieu group
to a bit matrix operating on a Golay code word.
Module make_mul_transp
The module contains class BitMatrixMulTransp
.
Class BitMatrixMulTransp
contains a directive that generates
code to multiply a bit vector with the transposed matrix of a
fixed bit matrix. Depending on the size of the matrix and the
bit length of the underlying integer type, several bit vectors
can be multiplied with the same matrix simultaneously.
The C function mat24_autpl_set_qform
uses that matrix
multiplication, see section Implementing Automorphisms of the Parker loop
in the Guide for developers for background.
Description of the mmgroup.generators
extension
Module generators
contains the definition of the generators of the
monster, so that they may be used in C files. It also contains support
for the subgroups \(N_{0}\) of structure
\(2^{2+11+2\cdot11}.(\mbox{Sym}_3 \times M_{24})\) and
\(G_{x0}\) of structure \(2^{1+24}.\mbox{Co}_1\) of the
monster, as described in [Con85] and [Sey20]. Here
\(M{24}\) is the Mathieu group acting on 24 elements, and
\(\mbox{Co}_1\) is the automorphism group of the 24-dimensional
Leech lattice modulo 2.
Here we fully support the computation in the subgroup \(N_{0}\) based on the generators defined in this module, so that a word in the generators of \(N_{0}\) can easily be reduced to a standard form.
We also support the operation of the group \(G_{x0}\) on the
Leech lattice mod 2 and mod 3 (in some cases up to sign only). For a
full support of the subgroup \(G_{x0}\) we also have to compute
in a Clifford group, which is implemented in module clifford12
.
Our set of generators of the monster group is defined in section The Monster group. The C implementation of this set of generators is defined in section Header file mmgroup_generators.h.
The intersection \(N_{0} \cap G_{x0}\) is a group \(N_{x0}\)
of structure \(2^{1+24}.2^{11}.M_{24}\). The group \(M_{24}\)
(and, to some extent, also the group \(N_{x0}\)) is
supported by the C functions in file mat24_functions.c
.
The Leech lattice and the extraspecial group \(Q_{x0}\)
Let \(Q_{x0}\) the normal subgroup of \(G_{x0}\) of structure \(2^{1+24}\). Then \(Q_{x0}\) is an extraspecial 2 group and also a normal subgroup of \(G_{x0}\). Let \(\Lambda\) be the Leech lattice. The quotient of \(Q_{x0}\) by its center \(\{\pm1\}\) is isomorphic to \(\Lambda/2 \Lambda\), which is the Leech lattice modulo 2.
For \(e_i \in Q_{x0}\) let \(\tilde{e}_i\) be the vector in the Leech lattice (mod 2) corresponding to \(\pm e_i\). Then \(e_1^2 = (-1)^s\) for \(s = \langle\tilde{e}_1, \tilde{e}_1 \rangle /2\), where \(\langle.,.\rangle\) is the scalar product in the Leech lattice. For the commutator \([e_1, e_2]\) we have \([e_1, e_2] = (-1)^t\), \(t = \langle \tilde{e}_1, \tilde{e}_2 \rangle\).
Leech lattice encoding of the elements of \(Q_{x0}\)
An element of of \(Q_{x0}\) can be written uniquely as a product \(x_d \cdot x_\delta\), \(d \in \mathcal{P} , \delta \in \mathcal{C}^*\), see [Sey20], section 5. Here \(\mathcal{P}\) is the Parker loop and \(\mathcal{C}^*\) is the Golay cocode. We encode the element \(x_d \cdot x_\delta\) of \(Q_{x0}\) as an integer \(x\) as follows:
Here elements of the Parker loop and elements of the cocode are encoded as integers as in section The Parker loop and The Golay code and its cocode. \(\theta\) is the cocycle given in section The basis of the Golay code and of its cocode, and ‘\(\oplus\)’ means bitwise addition modulo 2. Note that a Parker loop element is 13 bits long (with the most significant bit denoting the sign) and that a cocode element is 12 bits long.
From this representation of \(Q_{x0}\) we obtain a
representation of a vector in the Leech lattice modulo 2 by
dropping sign bit, i.e. the most significant bit at position 24.
A vector addition in the Leech lattice modulo 2 can be done by
applying the XOR operator ^
to the integers representing
the vectors, ignoring the sign bit.
Special elements of the group \(Q_{x0}\)
We write \(\Omega\) for the positive element of the Parker
loop such that \(\tilde{\Omega}\) is the Golay code word
\((1,\ldots,1)\) as in [Con85] and [Sey20].
In this specifiction we also write \(\Omega\) for the
element \(x_{\Omega}\) of \(Q_{x0}\) and for the element
\(\tilde{x}_{\Omega}\) of the Leech lattice modulo 2 if the
domain of \(\Omega\) is clear from the context. Then
\(\Omega\) has Leech lattice encoding 0x800000
in
our chosen basis of the Golay code; and the element \(\Omega\)
of \(\Lambda/2 \Lambda\) corresponds to the standard
coordinate frame of the real Leech lattice.
For fast computations in the monster group it is vital to compute
in the centralizer of a certain short element \(x_{\beta}\)
of \(Q_{x0}\), where \(\beta\) is an even coloured element
of the Golay cocode, as described in [Sey20]. Here we
choose the cocode element \(\beta\) corresponding to the
element \((0,0,1,1,0,\ldots,0)\) of \(\mbox{GF}_2^{24}\).
Then the centralizer of \(x_{\beta}\) is isomorphic to the
a double cover baby monster group and contains the generators
\(\tau\) and \(\xi\) of the monster. We also write
\(\beta\) for the element \(x_{\beta}\) of \(Q_{x0}\)
and for the element \(\tilde{x}_{\beta}\) of
\(\Lambda/2 \Lambda\) in the same way as for the element
\(\Omega\). Then \(\beta\) has Leech lattice
encoding 0x200
in our chosen basis.
Module gen_leech_reduce.c
contains functions for rotating
arbitrary type-4 vectors in \(\Lambda/2 \Lambda\) to
\(\Omega\) and for rotating arbitrary type-2 vectors in
\(\Lambda/2 \Lambda\) to \(\beta\).
Computations in the Leech lattice modulo 3
For the construction of the subgroup \(G_{x0}\) of the monster
we also require the automorphism group \(\mbox{Co}_0\) of the
real Leech lattice, as decribed in [Con85]. That group has
a faithful representation as an automophism group of
\(\Lambda/3 \Lambda\), but not of \(\Lambda/2 \Lambda\).
Module gen_leech3.c
provides functions for computing in the
Leech Lattice modulo 3.
Note that in [Sey20] the operation of the generators \(x_d, y_d, x_\delta, x_\pi, \xi\) of \(G_{x0}\) is also defined on the real Leech lattice.
Header file mmgroup_generators.h
The header file mmgroup_generators.h
contains definitions for the C files in the generator
extension. This extension comprises files mm_group_n.c
, gen_xi_functions.c
, and gen_leech.c
.
In this header we also define an enum MMGROUP_ATOM_TAG_
that specifies the format of an atom that acts as a generator of the monster group.
Defines
-
MMGROUP_ATOM_TAG_ALL
Tag field of a monster group atom
-
MMGROUP_ATOM_DATA
Data field of a monster group atom
-
gen_leech2_def_mul(x1, x2, result)
Macro version of function
gen_leech2_mul
.Macro
gen_leech2_def_mul(x1, x2, result)
is equivalent to the statementresult = gen_leech2_mul(x1, x2)
. The macro generates a sequence of statements!Caution:
Here
result
must be an integer lvalue that is different from both integers,x1
andx2
!
Enums
-
enum MMGROUP_ATOM_TAG_
In this header file we also define the tags for the atoms generating the Monster group. An element of the monster group is represented as an array of integers of type
uint32_t
, where each integer represents an atom, i.e. an atomic element of the monster. An atom represents a triple(sign, tag, value)
, and is encoded in the following bit fields of an unsigned 32-bit integer:Bit 31 | Bit 30,...,28 | Bit 27,...,0 --------|----------------|---------------- Sign | Tag | Value
Standard tags and values are defined as in the constructor of the Python class
mmgroup.mm
, see section The monster group in the API reference. If thesign
bit is set, this means that the atom bit given by the pair(tag, value)
has to be inverted. In ibid., a tag is given by a small letter. These small letters are converted to 3-bit numbers as follows:Tag | Tag number | Range of possible values i -----|------------|---------------------------- 'd' | 1 | 0 <= i < 0x1000 'p' | 2 | 0 <= i < 244823040 'x' | 3 | 0 <= i < 0x2000 'y' | 4 | 0 <= i < 0x2000 't' | 5 | 0 <= i < 3 'l' | 6 | 0 <= i < 3
A tag with tag number 0 is interpreted as the neutral element. A tag with tag number 7 is illegal (and reserved for future use).
Tags with other letters occuring in the constructor of class
MM
are converted to a word of atoms with tags taken from the table above.For tags ‘t’ and ‘l’ the values 0 <= i <= 3 are legal on input.
Values:
-
enumerator MMGROUP_ATOM_TAG_1
Tag indicating the neutral element of the group
-
enumerator MMGROUP_ATOM_TAG_I1
Tag indicating the neutral element of the group
-
enumerator MMGROUP_ATOM_TAG_D
Tag corresponding to ‘d’
-
enumerator MMGROUP_ATOM_TAG_ID
Tag corresponding to inverse of tag ‘d’
-
enumerator MMGROUP_ATOM_TAG_P
Tag corresponding to ‘p’
-
enumerator MMGROUP_ATOM_TAG_IP
Tag corresponding to inverse of tag ‘p’
-
enumerator MMGROUP_ATOM_TAG_X
Tag corresponding to ‘x’
-
enumerator MMGROUP_ATOM_TAG_IX
Tag corresponding to inverse of tag ‘x’
-
enumerator MMGROUP_ATOM_TAG_Y
Tag corresponding to ‘y’
-
enumerator MMGROUP_ATOM_TAG_IY
Tag corresponding to inverse of tag ‘y’
-
enumerator MMGROUP_ATOM_TAG_T
Tag corresponding to ‘t’
-
enumerator MMGROUP_ATOM_TAG_IT
Tag corresponding to inverse of tag ‘t’
-
enumerator MMGROUP_ATOM_TAG_L
Tag corresponding to ‘l’
-
enumerator MMGROUP_ATOM_TAG_IL
Tag corresponding to inverse of tag ‘l’
-
enumerator MMGROUP_ATOM_TAG_1
C functions implementing the group \(N_{0}\)
We describe an implementation of the subgroup \(N_{0}\) of the monster group.
The subgroup \(N_{0}\) of the monster group of structure
\(2^{2+11+2\cdot 11}.(\mbox{Sym}_3 \times\mbox{M}_{24})\) has been
described in [Con85]. Theorem 5.1 in [Sey20] reduces the
group operation in \(N_{0}\) to easy calculations in the Parker loop
\(\mathcal{P}\), the Colay cocode \(\mathcal{C}^*\), and the group
\({{\rm Aut}_{{\rm St}} \mathcal{P}}\) of standard automorphisms of
\(\mathcal{P}\). The loops \(\mathcal{P}\), \(\mathcal{C}^*\),
and \({{\rm Aut}_{{\rm St}} \mathcal{P}}\) are described in section
Basic structures. Module mat24_functions.c
provides the required
functions for computing in these loops.
Using the notation in section The Monster group we may describe an element of \(N_{0}\) as a product:
This representation is unique if we require \(f\) to be in a transversal of \(\mathcal{P} / Z(\mathcal{P})\) and \(\pi\) to be a standard representative in \({{\rm Aut}_{{\rm St}} \mathcal{P}}\) as described in section Automorphisms of the Parker loop.
We store an element of \(N_{0}\) an a quintuple
\(t, f, e, \delta, \pi\) of five integers of type uint32_t
.
For \(f, e\) we use the numbering in class PLoop
in module
mmgroup
; for \(\delta\) we use the numbering in class
Cocode
in module mmgroup
. Here \(\pi\) refers to a standard
representative in \({{\rm Aut}_{{\rm St}} \mathcal{P}}\). These
standard representatives correspond to the elements of the Mathieu
group \(\mbox{M}_{24}\); and we use the numbering of the elements
of \(\mbox{M}_{24}\) described in class AutPL|
in module
mmgroup
.
Most functions in module mm_group_n.c
take a pointer to a 5-tuple
\((t, f, e, \delta, \pi)\) representing an element \(g\)
of the \(N_{0}\) as their first argument. Then the tuple
representing \(g\) is modified to a tuple representing an
element \(g_2 = g \cdot g_1\), with the element \(g_1\) of
\(N\) given by one or more subsequent arguments of the function.
The functions in module mm_group_n.c
may cause some overhead due
to the fact that element of the Mathieu group \(\mbox{M}_{24}\)
is represented as an integer. But compared to an operation of the
monster group on its 196884-dimensional that overhead is negligible.
C interface for file mm_group_n.c
The functions in file mm_group_n.c
implement the subgroup \(N_0\) of structure \(2^{2+11+2\cdot11}.(\mbox{Sym}_3 \times \mbox{Mat}_{24})\) on the monster group. Elements of \(N_0\) are represented as arrays of five integers of type uint32_t
as described in the document The C interface of the mmgroup project.
Functions
-
void mm_group_n_mul_delta_pi(uint32_t *g, uint32_t delta, uint32_t pi)
Multiply \(g \in N_{0}\) with \(x_\delta x_\pi\).
Put \(g = g x_\delta x_\pi\). Here the integer \(\delta\) represents an element of the Golay cocode and \(\pi\) is the number of an element of \(M_{24}\) corresponding to a standard representative in the automorphism group \(\mbox{AUT}{(\mbox{PL})}\) of the Parker loop.
\(g\) is given as an array of five 32-bit integers.
-
void mm_group_n_mul_inv_delta_pi(uint32_t *g, uint32_t delta, uint32_t pi)
Multiply \(g \in N_{0}\) with \((x_\delta x_\pi)^{-1}\).
Put \(g = g \cdot (x_\delta x_\pi)^{-1}\). Here \(g\), \(x_\delta\), and \(x_\pi\) are as in function
mm_group_n_mul_delta_pi
.
-
void mm_group_n_mul_x(uint32_t *g, uint32_t e)
Multiply \(g \in N_{0}\) with \(x_e\).
Put \(g = g \cdot x_e\). Here the integer \(e\) represents an element of the Parker loop.
\(g\) is given as an array of five 32-bit integers.
-
void mm_group_n_mul_y(uint32_t *g, uint32_t f)
Multiply \(g \in N_0\) with \(y_f\).
Put \(g = g \cdot y_f\). Here the integer \(f\) represents an element of the Parker loop.
\(g\) is given as an array of five 32-bit integers.
-
void mm_group_n_mul_t(uint32_t *g, uint32_t t)
Multiply \(g \in N_0\) with the triality element.
Put \(g = g \cdot \tau^t\), where \(\tau\) is the triality element. \(g\) is given as an array of five 32-bit integers.
-
void mm_group_n_clear(uint32_t *g)
Set \(g \in N_0\) to the value of the neutral element.
Put \(g = 1\). Element \(g\) of \(N_0\) is given as an array of five 32-bit integers.
-
void mm_group_n_copy_element(uint32_t *g_1, uint32_t *g_2)
Copy the element \(g_1\) of \(N_0\) to \(g_2\).
Elements \(g_1, g_2\) of \(N_0\) are given as arrays of five 32-bit integers.
-
void mm_group_n_mul_element(uint32_t *g_1, uint32_t *g_2, uint32_t *g_3)
Multiply elemnts of the group \( N_0\).
Put \(g_3 = g_1 \cdot g_2\). Elements \(g_1, g_2, g_3\) of \(N_0\) are given as an array of five 32-bit integers.
These arrays may overlap.
-
void mm_group_n_mul_inv_element(uint32_t *g_1, uint32_t *g_2, uint32_t *g_3)
Multiply \(g_1 \in N_0\) with \(g_2^{-1} \in N_0\).
Put \(g_3 = g_1 \cdot g_2^{-1}\). Elements \(g_1, g_2, g_3\) of \(N_0\) are given as arrays of five 32-bit integers.
These arrays may overlap.
-
void mm_group_n_inv_element(uint32_t *g_1, uint32_t *g_2)
Invert an element \(g_1\) of \(N_0\).
Put \(g_2 = g_1^{-1}\). Elements \(g_1, g_2\) of \(N_0\) are given as arrays of five 32-bit integers.
These arrays may overlap.
-
void mm_group_n_conjugate_element(uint32_t *g_1, uint32_t *g_2, uint32_t *g_3)
Conjugate \(g_1 \in N_0\) with \(g_2 \in N_0\).
Put \(g_3 = g_2^{-1} \cdot g_1 \cdot g_2\). Elements \(g_1, g_2, g_3\) of \(N_0\) are given as arrays of five 32-bit integers.
These arrays may overlap.
-
uint32_t mm_group_n_mul_word_scan(uint32_t *g, uint32_t *w, uint32_t n)
Multiply \(g \in N_0\) with an element of the monster.
Let
w
be a word of generators of the monster group of lengthn
. Letk
be the greatest number such that all prefixes ofw
of length at mostk
are in the group \(N_{0}\). Let \(a\) be the element of \(N_{0}\) corresponding to the prefix ofw
of lengthk
.Let \(g \in N_{0}\) is given as an array
g
of five 32-bit integers.Then the function replaces the value \(g\) in the array
g
by \(g \cdot a\). It returns the numberk
of atoms of the wordw
processed.
-
uint32_t mm_group_n_mul_atom(uint32_t *g, uint32_t atom)
Multiply \(g \in N_{0}\) with an atom.
Put \(g = g \cdot a\). Here \(a\) is the generator of the group \(N_0\) given by parameter
atom
as described in the header filemmgroup_generators.h
.\(g\) is given as an array of five 32-bit integers.
The function returns 0 in case of success and the (possibly simplified) atom in case of failure.
-
uint32_t mm_group_n_scan_word(uint32_t *w, uint32_t n)
Scan word of generators of the monster for membership in \(N_{0}\).
Let
w
be a word of generators of the monster group of lengthn
. The function returns the greatest numberk
such that all prefixes ofw
of length at mostk
are in the group \(N_{0}\).
-
uint32_t mm_group_n_conj_word_scan(uint32_t *g, uint32_t *w, uint32_t n)
Conjugate \(g \in N_0\) with an element of the monster.
Let
w
be a word of generators of the monster group of lengthn
. Letk
be the greatest number such that all prefixes ofw
of length at mostk
are in the group \(N_{0}\). Let \(a\) be the element of \(N_{0}\) corresponding to the prefix ofw
of lengthk
.Let \(g \in N_{0}\) is given as an array
g
of five 32-bit integers.Then the function replaces the value \(g\) in the array
g
by \(a^{-1} \cdot g \cdot a\). It returns the numberk
of atoms of the wordw
processed.
-
uint32_t mm_group_n_reduce_element(uint32_t *g)
Reduce \(g \in N_0\) to a standard form.
The representation of \(g\) is reduced to a standard form.
Technically, we reduce the product \(y_f x_e\) to \(y_{f'} x_{e'}\), such that \(0 \leq f' < \mbox{0x800}\) holds. If \(x_e\) is in the center of the Parker loop, but \(x_f\) is not in that center then we put \(x_{e'}=0\).
\(g\) is given as an array of five 32-bit integers.
-
uint32_t mm_group_n_reduce_element_y(uint32_t *g)
Reduce \(g \in N_0\) to a standard form.
The representation of \(g\) is reduced to a standard form.
Here we reduce the product \(y_f x_e\) to \(y_{f'} x_{e'}\), such that \(0 \leq f' < \mbox{0x800}\) always holds.
\(g\) is given as an array of five 32-bit integers.
-
uint32_t mm_group_n_to_word(uint32_t *g, uint32_t *w)
Convert \(g \in N_0\) to a word of generators.
The representation of \(g\) is converted to a word of generators of the monster group. The entries of that word are stored in the buffer referred by parameter
w
. The entries of that word are encoded as described in filemmgroup_generators.h
. Wordw
may have up to five entries. The function returns the length of the wordw
.\(g\) is given as an array of five 32-bit integers.
The element \(g\) is reduced with function
mm_group_n_reduce_element
.It is legal to put
w
=g
.
-
uint32_t mm_group_n_right_coset_N_x0(uint32_t *g)
Map \(g \in N_0\) to an element of \(N_{x0}\).
The function changes the element \(g\) of \(N_0\) to an element \(g'\) of \(N_{x0}\) and returns an exponent \(0 \leq e < 3\) such that \(g = g' \cdot \tau^e\).
-
uint32_t mm_group_n_to_word_std(uint32_t *g, uint32_t *w)
Convert \(g \in N_0\) to a standard word of generators.
The representation of \(g\) is converted to a word of generators of the monster group in the standard order. The entries of that word are stored in the buffer referred by parameter
w
.The standard order of the generators of the monster group in the reduced representation of an element of \(N_0\) differs from the order of the generators returned by function
mm_group_n_to_word
. Apart from this difference the action of this function is the same as in that function.It is legal to put
w
=g
.
-
int32_t mm_group_n_conj_to_Q_x0(uint32_t *g)
Transform element of \(N_0\) to an element of \(Q_{x0}\).
Let \(g \in N_x0\) be stored in the array
g
of five 32-bit integers.The function tries to calculate a number \(0 \leq e < 3\) and an element \(q\) of the subgroup \(Q_{x0}\) of \(N_0\) with \(g = \tau^{-e} q \tau^e\). Here \(\tau\) is the triality element in \(N_0\).
In case of succes we return the element \(q\) in bits 24,…,0 of the return value in Leech lattice encoding and we return the number \(e\) in bits 26,…,25 of the return value. In case of failure we return -1.
-
uint32_t mm_group_split_word_n(uint32_t *word, uint32_t length, uint32_t *g)
Split an element of \(N_0\) from a word of generators.
Given a array
word
of generators of the monster group of a givenlength
, that word is split into a possibly shorter wordword1
and an elementg
of the group \(N_0\) such thatword
=word1
*g
. Thenword1
is a prefix ofword
. The function returns the length of the prefixword1
ofword
. It does not changeword
. Here we just scan theword
from the right, checking for atoms ordered in a way compatible to our representation of \(N_0\).Words of generators of the monster are implemented as described in file
mmgroup_generators.h
. Output \(g\) is given as an array of five 32-bit integers.
-
uint32_t mm_group_mul_words(uint32_t *w1, uint32_t l1, uint32_t *w2, uint32_t l2, int32_t e)
Multiply a word of generators of the monster.
Given a word
w1
of lengthl1
and a wordw2
of lengthl2
of generators of the monster group, we compute the productw3
=w1 * w2**e
. Here**
means exponentiation; negative exponents are supported. The wordw1
is replaced by the wordw3
. The funcion returns the length of the wordw3
.A word representing
w2**e
is appended to wordw1
and then the result is simplified using the relations inside the group \(N_0\). The resultw3
is reduced (with respect to these relations) if inputw1
is reduced.Caution!
The buffer for the word
w1
referred by pointerw1
must be able to store at leastl1 + 2 * abs(e) * l2
entries of typeuint32_t
. Here the user must provide sufficient space!Words of generators of the monster are implemented as described in file
mmgroup_generators.h
.
-
void mm_group_invert_word(uint32_t *w, uint32_t l)
Invert a word of generators of the monster.
Given a word
w
of lengthl
the function changes the word in the bufferw
to its inverse in place.Words of generators of the monster are implemented as described in file
mmgroup_generators.h
.
-
uint32_t mm_group_check_word_n(uint32_t *w1, uint32_t l1, uint32_t *g_out)
Check if a words of generators of the monster is in \(N_0\).
We check if the word
w1
of lengthl1
of generators of the monster group is in the subroup \(N_0\). If this is the case then we store the wordw1
as an element of \(N_0\) in the arrayg_out
of five 32-bit integers as desribed above. The function returns the following status information:0:
w1
is the neutral element the monster group1:
w1
is in \(N_0\), but not the neutral element2:
w1
is not in \(N_0\)3: Nothing is known about
w1
We check the relations in the generators \(N_0\) only. The output in
g_out
is valid only if the function returns 0 or 1.Words of generators of the monster are implemented as described in file
mmgroup_generators.h
.
-
uint32_t mm_group_words_equ(uint32_t *w1, uint32_t l1, uint32_t *w2, uint32_t l2, uint32_t *work)
Check if two word of generators of the monster are equal.
We check if the word
w1
of lengthl1
of generators of the monster group is equal to the wordw2
of lengthl2
of generators. The function returns the following status information:0:
w1
==w2
1:
w1
!= `w2
Greater than 1: equality of
w1
andw2
is not knownIf the function cannot check the equality of
w1
andw2
then it computes a wordw3
of lengthl3
of generators of the monster group such thatw1
==w2
if and only ifw3
is the neutral element. Then the function stores the wordw3
in the bufferwork
and it returnsl3 + 2
.Buffer
work
must have size at leastmax(2 * l1, l1 + 2 * l2)
.Words of generators of the monster are implemented as described in file
mmgroup_generators.h
.
C functions for the operation of \(G_{x0}\) on the Leech lattice
The functions in file gen_leech.c
implement the operation of the
subgroup \(G_{x0}\) (of structure \(2^{1+24}.\mbox{Co}_1\))
of the monster group on its extraspecial subgroup \(Q_{x0}\)
(of structure \(2^{1+24}\)) by conjugation.
Here an element of the group \(Q_{x0}\) is given as a 25-bit integer in Leech lattice encoding. From that encoding we obtain an encoding of \(\Lambda / 2 \Lambda\) (where \(\Lambda\) is the Leech lattice) by dropping the most significant bit. This corresponds to the isomorphism \(Q_{x0} / \{\pm1\} \cong \Lambda / 2 \Lambda\).
An element of the group \(G_{x0}\) is encoded as an array of
32-bit integers, where each integer corresponds to a generator of
the group, as described in the documentation of the header file
mmgroup_generators.h
.
A vector in the Leech lattice modulo 2 has a type and also a subtype
as described in The mmgroup guide for developers, section
Computations in the Leech lattice modulo 2. Here the subtype is a two-digit decimal
number, where the first digit is the type. Function
gen_leech2_subtype
returns the subtype as a BCD-coded integer.
E.g. the subtype 46 is returned as the hexadecimal integer 0x46.
So the type can be obtained from the subtype via a shift operation.
For computations in the group \(G_{x0}\) or \(\mbox{Co}_1\)
it is important to find an element of \(G_{x0}\) that maps an
arbitrary type-4 vector in \(\Lambda / 2 \Lambda\) to the unique
type-4 vector \(\Omega\), see Computations in the Leech lattice modulo 2.
Function gen_leech2_reduce_type4
performs this task.
The construction of the group \(G_{x0}\) also requires some
computations in the automorphism group \(\mbox{Co}_0\)
(of structure \(2.\mbox{Co}_1\)) of \(\Lambda\), see
[Con85], section 9 or [Sey20], section 9. The group
\(\mbox{Co}_0\) acts faithfully on \(\Lambda / 3 \Lambda\).
Therefore file gen_leech.c
also provides some functions for
dealing with vectors in the Leech lattice modulo 3.
For any \(w \in \Lambda\) the vector
\(v = \sqrt{8} \cdot w\) has integral coordinates. We
represent a vector \(w \in \Lambda / 3 \Lambda\) by the vector
\(v = \sqrt{8} \cdot w\), with the coordinates of \(v\)
taken modulo 3. We represent each coordinate
\(v_i, 0 \leq i < 24\) as a two-bit integer;
so all 48 bits of \(v\) fit into the a 64-bit integer. Let
\(v_{i,1}, v_{i,0}\) be the bits of \(v_{i}\) of
valence \(2^1\) and \(2^0\), respectively. Then we
encode \(v\) as an 48-bit integer \(x\) so that bit
\(24 \cdot j+i\) of \(x\) is equal to \(v_{i,j}\).
This encoding looks peculiar, but it greatly simplifies the
interaction with the functions in file mat24_functions.c
. We
call this encoding the Leech lattice mod 3 encoding.
On input, both bits \(v_{i,1}, v_{i,0}\) may be equal to 1;
but on output, at most on of these bits is equal to 1.
In [Sey20], section 9.3, the generators \(x_d, x_\delta, y_\delta, x_\pi, \xi\) of \(G_{x0}\) are also defined as generators of a group \(G_{x1}\) with \(|G_{x1}:G_{x0}| = 2\). The group \(G_{x1}\) operates on \(\Lambda\), but the group \(G_{x0}\) does not. So we take these generators as generators of \(G_{x1}\). The kernel of the operation of \(G_{x1}\) on \(\Lambda\) is the group \(Q_{x0}\) generated by the elements \(x_d, x_\delta, y_{-1}, d \in \mathcal{P}, \delta \in \mathcal{C}\). Here the element \(y_{\Omega}\) acts as the central element \(-1\).
C interface for file gen_leech.c
The functions in file gen_leech.c
implement operations on the vectors of the Leech lattice modulo 2 and on the subgroup \(Q_{x0}\). We use the terminology defined in the document The C interface of the mmgroup project, section Description of the mmgroup.generators extension.
Functions
-
uint32_t gen_leech2_mul(uint32_t x1, uint32_t x2)
Return product of two elements the group \(Q_{x0}\).
Here all elements of the group \(Q_{x0}\) are encoded in
Leech lattice encoding
. The function returns the product of the elementsx1
andx2
of \(Q_{x0}\).
-
uint32_t gen_leech2_pow(uint32_t x1, uint32_t e)
Return power of element the group \(Q_{x0}\).
Here all elements of the group \(Q_{x0}\) are encoded in
Leech lattice encoding
. The function returns the powerx1**e
of the elementx1
of \(Q_{x0}\).
-
uint32_t gen_leech2_scalprod(uint32_t x1, uint32_t x2)
Return scalar product in the Leech lattice modulo 2.
Here all elements of Leech lattice modulo 2 are encoded in
Leech lattice encoding
. The function returns the scalar product of the vectorsx1
andx2
in the Leech lattice modulo 2, which may be 0 or 1.
-
uint32_t gen_leech2_op_word(uint32_t q0, uint32_t *g, uint32_t n)
Perform operation of \(G_{x0}\) on \(Q_{x0}\).
The function returns the element \(g^{-1} q_0 g\) for \(q_0 \in Q_{x0}\) and \(g \in G_{x0}\). Here \(g\) is given as a word of genenators of length \(n\) in the array
g
. Each atom of the word \(g\) is encoded as defined in the header filemmgroup_generators.h
. The element \(q_0\) and its image under \(g\) are encoded in Leech lattice encoding.The function succeeds also in case \(g \notin G_{x0}\) if \(h^{-1} q_0 h \in G_{x0}\) for all prefixes \(h\) of \(g\).
Parameter \({q_0}\) and the result are given Leech lattice encoding.
-
uint32_t gen_leech2_op_atom(uint32_t q0, uint32_t g)
Atomic operation of \(G_{x0}\) on \(Q_{x0}\).
Equivalent to
gen_leech2_op_word(q0, &g, 1)
.
-
uint32_t gen_leech2_prefix_Gx0(uint32_t *g, uint32_t len_g)
Scan prefix in \(G_{x0}\) of a word in the monster group.
Let \(g \in G_{x0}\) be stored in the array
g
of lengthlen_g
as a word of generators of the subgroup \(G_{x0}\) of the monster. The function returns the maximum lengthlen_g
such that every prefix of the word ing
of length<= len_g
is in the group \(G_{x0}\).
-
uint32_t gen_leech2_op_word_many(uint32_t *q, uint32_t m, uint32_t *g, uint32_t n)
Perform operation of \(G_{x0}\) on elements of \(Q_{x0}\).
Let
q
be an array ofm
elements \(q_j\) of the group \(Q_{x0}\) in Leech lattice encoding. Let \(g\) be an element of the group \(G_{x0}\) encoded in the arrayg
of lengthn
as in functiongen_leech2_op_word
.The function computes the elements \(q'_j = g^{-1} q_j g\) for \(0 \leq j < m\) and stores \(q'_j\) in
a[j]
.The function applies the same prefix of the word in the array
g
to all entries ofq
. It stops if the application of any prefix of the word ing
to any element \(q_j\) fails; and it returns the length of the prefix ofa
that has been applied to all elements \(q_j\). Hence the function returnsn
in case of success and a number0 \leq k < n
if not all atoms ofq
could be applied to all entries ofq
.The function succeeds on an individual entry \(q_j\) if and only if function
gen_leech2_op_word
succeeds on the same value.
-
uint32_t gen_leech2_op_word_leech2(uint32_t l, uint32_t *g, uint32_t n, uint32_t back)
Perform operation of \(G_{x0}\) on Leech lattice mod 2.
Let \(g_0 \in G_{x0}\) be stored in the array referred by
g
as a word of generators of the subgroup \(G_{x0}\) of the monster. Here \(g_0\) is given as a word of generators of length \(n\) in the arrayg
. Each atom of the word \(g\) is encoded as defined in the header filemmgroup_generators.h
. Put \(g = g_0\) ifback == 0
and \(g = g_0^{-1}\) otherwise.The function returns the element \(l \cdot g\) for a vector \(l\) in the Leech lattice mod 2.
Parameter \(l\) is encoded in Leech lattice encoding, igoring the sign. The function returns \(l \cdot g\), in Leech lattice encoding, with the sign bit set to zero.
The function is optimized for speed. It returns garbage if any generator in the buffer
g
is not in \(G_{x0}\).
-
int32_t gen_leech2_op_word_leech2_many(uint32_t *a, uint32_t m, uint32_t *g, uint32_t n, uint32_t back)
Perform operation of \(G_{x0}\) on elements ofLeech lattice mod 2.
Let
a
be an array ofm
elements \(l_j\) of the Leech lattice mod 2 in Leech lattice encoding. Let \(g_0\) be an element of the group \(G_{x0}\) encoded in the arrayg
of lengthn
as in functiongen_leech2_op_word
. Put \(g = g_0\) ifback == 0
and \(g = g_0^{-1}\) otherwise.The function replaces each element \(l_j\) in the array
m
by \(l_j \cdot g\). Elements \(l_j\) are encoded in Leech lattice encoding, igoring the sign.The function is optimized for speed. It returns zero in case of success. It stores garbage in the array
m
and returns a negative value if any generator in the bufferg
is not in \(G_{x0}\).
-
int32_t gen_leech2_op_word_matrix24(uint32_t *g, uint32_t n, uint32_t back, uint32_t *a)
Convert operation of group \(G_{x0}\) to 24 times 24 bit matrix.
Let \(g_0 \in G_{x0}\) be stored in the array referred by
g
as a word of generators of the subgroup \(G_{x0}\) of the monster. Here \(g_0\) is given as a word of generators of length \(n\) in the arrayg
. Each atom of the word \(g\) is encoded as defined in the header filemmgroup_generators.h
. Put \(g = g_0\) ifback == 0
and \(g = g_0^{-1}\) otherwise.The function converts \(g\) to a \(24 \times 24\) bit matrix \(a\) acting on the vectors of the Leech lattice mod 2 (encoded in Leech lattice encoding) by right multiplication. Such matrices form a natural representation of the Conway group \(\mbox{Co}_1\).
The function returns 0 in case of success and a negative value in case of error.
-
void gen_leech2_op_mul_matrix24(uint32_t *a1, uint32_t n, uint32_t *a)
Multiply an n times 24 bit matrix with a 24 times 24 bit matrix.
The function multiplies the
n
times 24 bit matrixa1
with the 24 times 24 bit matrixa
and stores the result in matrixa1
.Thus array
a1
must have lengthn
; and arraya1
must have length 24.
-
int32_t gen_leech2_map_std_subframe(uint32_t *g, uint32_t len_g, uint32_t *a)
Transform the standard subframe of Leech lattice mod 2
A frame in the Leech lattice \(\Lambda\) is a maximal set of pairwise orthogonal vectors of type 4. In \(\Lambda / 2 \Lambda\) (which is the Leech lattice mod 2) a frame is mapped to a unique vector of type 4. The standard frame \(\Omega\) in \(\Lambda\) consists of the type-8 vectors parallel to the basis vectors in \(\Lambda\).
The subframe \(S(F)\) of a frame \(F\) in \(\Lambda\) is the set \(\{ (u + v)/2 \mid u, v \in F, u \neq \pm v\}\). Any frame \(S(F)\) in \(\Lambda\) contains \(48\) type-4 vectors, and its subframe contains \(48 \cdot 46\) type-2 vectors.
The image of \(S(F)\) in \(\Lambda / 2 \Lambda\) spans a 12-dimensional maximal isotropic subpace \(\langle S(F) \rangle\) of \(\Lambda / 2 \Lambda\), and the type-2 vectors in \(\langle S(F) \rangle\) are precisely images of \(S(F)\).
Then for the standard frame \(\Omega\) we have
\( \langle S(\Omega) \rangle = \{ \lambda_\delta, \lambda_\Omega + \lambda_\delta \mid \delta \in \mathcal{C}^*, \delta \, \mbox{even} \} \) .
Here \(\mathcal{C}^*\) is the Golay cocode, and and \(\lambda_c\) is the element of \(\Lambda / 2 \Lambda\) corresponding to the Golay code or cocode element \(c\).
Then \(\langle S(\Omega) \rangle\) is spanned by \(\lambda_\Omega\) and \(\lambda_{\{0,j\}}, 1 \leq j < 24\). Here \(\{i,j\}\) is the Golay cocode word corresponding to the sum of basis vectors \(i\) and \(j\) of \(\mbox{GF}_2^{24}\).
The elements \(x_\Omega\) and \(x_{\{0,j\}}\) of the group \(Q_{x0}\) are preimages of \(\lambda_\Omega\) and \(\lambda_{\{0,j\}}\) under the natural homomorphism from \(Q_{x0}\) to \(\Lambda / 2 \Lambda\). These elements of \(Q_{x0}\) play an important role in the representation \(196883_x\) of the monster group. For computations in the subgroup \(G_{x0}\) of the monster we sometimes want to compute the images of these elements of \(Q_{x0}\) under conjugation by an element \(g\) of \(G_{x0}\).
Let \(g \in G_{x0}\) be stored in the array
g
of lengthlen_g
as a word of generators of the subgroup \(G_{x0}\) of the monster. Then this function computes the following 24 elements of \(Q_{x0}\):\( x_\Omega^g, x_{\{0,1\}}^ g, \ldots, x_{\{0,23\}}^g\).
The function stores these 24 elements in the array
a
(in that order) in Leech lattice encoding.In case of success the function returns the number of entries of the word
g
being processed. It returns a negative value in case of failure.
C interface for file gen_leech_type.c
The functions in file gen_leech_type.c
implement operations for detecting the type of a vector in the Leech lattice modulo 2.
We use the terminology defined in the document The C interface of the mmgroup project, section Description of the mmgroup.generators extension.
Functions
-
uint32_t gen_leech2_subtype(uint64_t v2)
Return subtype of vector in Leech lattice mod 2.
The function returns the subtype of the vector \(v_2\) in the Leech lattice modulo 2 as a BCD-coded two-digit integer. \(v_2\) must be given in Leech lattice encoding.
The subtype of a vector in the Leech lattice mod 2 is defined in The mmgroup guide for developers, section Computations in the Leech lattice modulo 2.
-
uint32_t gen_leech2_type(uint64_t v2)
Return type of a vector in the Leech lattice mod 2.
This function returns the type of the vector \(v_2\) in the Leech lattice modulo 2. That type may be 0, 2, 3, or 4.
This function is a bit faster than function
gen_leech2_subtype()
.
-
uint32_t gen_leech2_type2(uint64_t v2)
Compute subtype if vector in Leech lattice mod 2 is of type 2.
This function returns the subtype of the vector \(v_2\) in the Leech lattice modulo 2 if \(v_2\) is of type 2 and 0 otherwise.
It is faster than function
gen_leech2_type()
.
-
uint32_t gen_leech2_count_type2(uint32_t *a, uint32_t n)
Count type-2 vectors in an affine subspace of the Leech lattice mod 2.
This function returns the number of type-2 vectors in an affine subspace \(V\) of the Leech lattice mod 2. Subspace \(V\) is defined by an array \(a\) of length \(n\) of bit vectors. If \(a_1,\ldots,a_{n-1}\) are linear independent then \(V\) is given by:
\(V = \{a_0 + \sum_{i=1}^{n-1} \lambda_i a_i \mid \lambda_i=0,1\}\).
-
int32_t gen_leech2_start_type24(uint32_t v)
Auxiliary function for function gen_leech2_reduce_type4.
The function returns the subtype of a vector \(v\) of type 2 in the Leech lattice modulo 2, provided that \(v + \beta\) is of type 4. It returns 0 in the special case \(v = \beta + \Omega\) and a negative value if \(v\) is not of type 2 or \(v + \beta\) is not of type 4.
It is used for rotating a type-4 vector \(v\) which is orthogonal to \(\beta\) (in the real Leech lattice) into the \(v + \Omega\). That rotation will fix the special short vector \(\beta\).
-
int32_t gen_leech2_start_type4(uint32_t v)
Auxiliary function for function gen_leech2_reduce_type4.
The function returns the subtype of a vector \(v\) of type 4 in the Leech lattice modulo 2. Parameter \(v\) must a vector of type 4 in Leech lattice encoding. The function returns the subtype of \(v\) that will be used for reduction in function
gen_leech2_reduce_type4
.This function takes care of the special vectors \(\Omega\) and \(\beta\) the Leech lattice modulo 2.
It is used for rotating a type-4 vector \(v\) into \(\Omega\). If this is possible, that rotation will fix the special short vector \(\beta\).
Therefore the function returns 0 in case \(v = \Omega\). It returns the subtype of \(v + \beta\) if \(\beta\) and \(v + \beta\) are of type 2 and orthogonal in the real Leech lattice.
The function returns a negative value if \(v\) is not of type 4.
C interface for file gen_leech3.c
The functions in file gen_leech3.c
implement operations on the vectors of the Leech lattice modulo 3 and on the subgroup \(Q_{x0}\). We use the terminology defined in the document The C interface of the mmgroup project, section Description of the mmgroup.generators extension.
Functions
-
uint32_t gen_leech3_scalprod(uint64_t v3_1, uint64_t v3_2)
Scalar product of two vectors in the Leech lattice mod 3.
The function returns the scalar product of the vectors \(v_{3,1}, v_{3,2}\). The parameters are given in Leech lattice mod 3 encoding. The result is between 0 and 2.
-
uint64_t gen_leech3_add(uint64_t v3_1, uint64_t v3_2)
Add two vectors in the Leech lattice mod 3.
The function returns the sum of the vectors \(v_{3,1}, v_{3,2}\). The parameters and the result are given in Leech lattice mod 3 encoding.
-
uint64_t gen_leech3_neg(uint64_t v3)
Negate a vector in the Leech lattice mod 3.
The function returns the negated vector \(v_{3}\). The parameter and the result are given in Leech lattice mod 3 encoding.
-
uint64_t gen_leech2to3_short(uint64_t v2)
Map short vector from \(\Lambda/2\Lambda\) to \(\Lambda/3\Lambda\).
Here parameter \(v_2\) is a short vector (i.e. a vector of type 2) in \(\Lambda/2\Lambda\) in Leech lattice encoding.
The function returns a short vector in \(\Lambda/3\Lambda\) corresponding to \(v_2\) in Leech lattice mod3 encoding.
The result is unique upto sign only. The function returns 0 if \(v_2\) is not short.
-
uint64_t gen_leech2to3_abs(uint64_t v2)
Map vector from \(\Lambda/2\Lambda\) to \(\Lambda/3\Lambda\).
Here parameter \(v_2\) is a short vector of type 2 or 3. in \(\Lambda/2\Lambda\) in Leech lattice encoding.
The function returns a vector in \(\Lambda/3\Lambda\) corresponding to \(v_2\) in Leech lattice mod3 encoding.
The result is unique upto sign only. The function returns 0 if \(v_2\) is not of type 2 or 3.
-
uint64_t gen_leech3to2_short(uint64_t v3)
Map short vector from \(\Lambda/3\Lambda\) to \(\Lambda/2\Lambda\).
Here parmeter \(v_3\) is a short vector (i.e. a vector of type 2) in \(\Lambda/3\Lambda\) in Leech lattice mod 3 encoding.
The function returns a short vector in \(\Lambda/2\Lambda\) corresponding to \(v_3\) in Leech lattice encoding.
The result is unique. The function returns 0 if \(v_3\) is not short. This function is an inverse of function
gen_leech2to3_short
.
-
uint64_t gen_leech3to2(uint64_t v3)
Map vector from \(\Lambda/3\Lambda\) to \(\Lambda/2\Lambda\).
Here parameter \(v_3\) is a vector in \(\Lambda/3\Lambda\) in Leech lattice mod 3 encoding.
If a shortest preimage \(v\) of \(v_3\) in \(\Lambda\) if of type \(t\) with \(t \leq 4\) then the function computes the (unique) vector \(v_2\) in \(\Lambda/2\Lambda\) that has the same preimage \(v\) in \(\Lambda\). Otherwise the function fails.
In case of success the function returns \(2^{24} \cdot t + v_2\), with \(v_2\) given in Leech lattice encoding. The function returns
uint64_t(-1)
in case of failure.
-
uint64_t gen_leech3to2_type4(uint64_t v3)
Map type-4 vector from \(\Lambda/3\Lambda\) to \(\Lambda/2\Lambda\).
Here parameter \(v_3\) must be a type-4 vector in \(\Lambda/3\Lambda\) in Leech lattice mod 3 encoding.
The function returns a type-4 vector in \(\Lambda/2\Lambda\) corresponding to \(v_3\) in Leech lattice encoding.
The result is unique. The function returns 0 if \(v_3\) is not of type 4.
-
uint64_t gen_leech3_op_xi(uint64_t v3, uint32_t e)
Special case of function
gen_leech3_op_vector_word
For internal purposes only. This is equivalent to
gen_leech3_op_vector_word(v3, g)
, whereg
encodes the element \(\xi^e\) of \(G_{x1}\).Parameter \({v_3}\) and the result are given Leech lattice mod 3 encoding.
-
uint64_t gen_leech3_op_vector_word(uint64_t v3, uint32_t *pg, uint32_t n)
Operation of \(G_{x1}\) on the Leech lattice mod 3.
The function returns the element \(v_3 g\) for \(v_3 \in \Lambda/3\Lambda\) and \(g \in G_{x0}\). Here \(g\) is given as a word of genenators of length \(n\) in the array
pg
. Each atom of the word \(g\) is encoded as defined in the header filemmgroup_generators.h
.Parameter \({v_3}\) and the result are given Leech lattice mod 3 encoding.
-
uint64_t gen_leech3_op_vector_atom(uint64_t v3, uint32_t g)
Atomic operation of \(G_{x1}\) on the Leech lattice mod 3.
Equivalent to
gen_leech3_op_vector_word(v3, &g, 1)
.Parameter \({v_3}\) and the result are given Leech lattice mod 3 encoding.
C interface for file gen_leech_reduce.c
The functions in file gen_leech_reduce.c
implement the transformation of vectors of the Leech lattice modulo 2 to a standard form by applying an element of the subgroup \(G_{x0}\) of the monster.
We use the terminology defined in the document The C interface of the mmgroup project, section Description of the mmgroup.generators extension.
Functions
-
int32_t gen_leech2_reduce_type2(uint32_t v, uint32_t *pg_out)
Map short vector in Leech lattice to standard vector.
Let \(v \in \Lambda / 2 \Lambda\) of type 2 be given by parameter
v
in Leech lattice encoding. Then the function constructs a \(g \in G_{x0}\) that maps \(v\) to the standard short vector \(v_0\). Here \(v_0\) is the short vector the Leech lattice propotional to \(e_2 - e_3\), where \(e_i\) is the \(i\)-th basis vector of \(\{0,1\}^{24}\).The element \(g\) is returned as a word in the generators of \(G_{x0}\) of length \(n \leq 6\). Each atom of the word \(g\) is encoded as defined in the header file
mmgroup_generators.h
.The function stores \(g\) as a word of generators in the array
pg_out
and returns the length \(n\) of that word. It returns a negative number in case of failure, e.g. if \(v\) is not of type 2.Caution:
An input vector allows several outputs. Changing the implementation of this function such that the same input leads to a different output destroys the interoperability between different versions of the project!!
-
int32_t gen_leech2_reduce_type2_ortho(uint32_t v, uint32_t *pg_out)
Map (orthogonal) short vector in Leech lattice to standard vector.
Let \(v \in \Lambda / 2 \Lambda\) of type 2 be given by parameter
v
in Leech lattice encoding.In the real Leech lattice, (the origin of) the vector \(v\) must be orthogonal to the standard short vector \(v_0\). Here \(v_0\) is the short vector in the Leech lattice propotional to \(e_2 - e_3\), where \(e_i\) is the \(i\)-th basis vector of \(\{0,1\}^{24}\).
Let \(v_1\) be the short vector in the Leech lattice proportional to \(e_2 + e_3\). Then the function constructs a \(g \in G_{x0}\) that maps \(v\) to \(v_1\) and fixes \(v_0\).
The element \(g\) is returned as a word in the generators of \(G_{x0}\) of length \(n \leq 6\). Each atom of the word \(g\) is encoded as defined in the header file
mmgroup_generators.h
.The function stores \(g\) as a word of generators in the array
pg_out
and returns the length \(n\) of that word. It returns a negative number in case of failure, e.g. if \(v\) is not of type 2, or not orthogonal to \(v_0\) in the real Leech lattice.Caution:
An input vector allow several outputs. Changing the implementation of this function such that the same input leads to a different output destroys the interoperability between different versions of the project!!
-
int32_t gen_leech2_reduce_type4(uint32_t v, uint32_t *pg_out)
Map a frame in the Leech lattice to the standard frame.
A frame in the Leech lattice \(\Lambda\) is a maximal set of type-4 vectors which are equal modulo \(2 \Lambda\). A frame is equivalent to a type-4 vector in \(\Lambda / 2 \Lambda\).
Let \(v \in \Lambda / 2 \Lambda\) of type 4 be given by parameter
v
in Leech lattice encoding. Then the function constructs a \(g \in G_{x0}\) that maps \(v\) to the standard frame \(\Omega\). The standard frame \(\Omega\) consists of the type-4 vectors parallel to the coordinate axes.The element \(g\) is returned as a word in the generators of \(G_{x0}\) of length \(n \leq 6\). Each atom of the word \(g\) is encoded as defined in the header file
mmgroup_generators.h
. Let \(H\) be the stabilizer of \(\Omega\). We choose a representative \(g\) in the coset \(gH\) such that the inverse \(g^{-1}\) is a short as possible.The function stores \(g\) as a word of generators in the array
pg_out
and returns the length \(n\) of that word. It returns a negative number in case of failure, e.g. if \(v\) is not of type 4.The function uses the method described in the
The mmgroup guide for developers
, sectionComputations in the Leech lattice modulo 2
.We make one additional assertion.
Let \(v_0\) be the standard short vector in the Leech lattice proportional to \(e_2 - e_3\), where \(e_i\) is the \(i\)-th basis vector of \(\{0,1\}^{24}\). If \(v_0 + v\) is of type 2 then this function computes the same result as function
gen_leech2_reduce_type2_ortho
applied to the vector \(v_0 + v\). In this case the result of this function centralizes \(v_0\). This convention greatly simplifies computations in the baby monster group.Caution:
An input vector allow several outputs. Changing the implementation of this function such that the same input leads to a different output destroys the interoperability between different versions of the project!!
-
uint32_t gen_leech2_type_selftest(uint32_t start, uint32_t n, uint32_t *result)
Test functions
gen_leech2_subtype
andgen_leech2_reduce_type4
Function
gen_leech2_subtype
may tested as follows:We compute the subtypes of all \(2^{24}\) vectors \(v \in \Lambda / 2 \Lambda\) and we count the obtained subtypes in an array
result
of length 0x50. The sizes of the orbits of each subtype are known form [Iva99], so a high-level test routine may check the arrayresult
.During that process we may also test function
gen_leech2_reduce_type4
. Whenever vector of type-4 vector \(v\) occurs, we compute ag \in G_{x0}
that maps \(v\) to the standard frame using functiongen_leech2_reduce_type4
; and we check the correctness of that mapping using functiongen_leech2_op_word
. We return the number of successful such operations. This number must be equal to the number of type-4 vectors in \(\Lambda / 2 \Lambda\).Since this test takes a long time, a high-level function might want to distribute it over several processes. So this function acccumulates the test results for the vectors \(v\) with \(\mbox{start} \leq v < \mbox{start} + \mbox{n}\) only.
-
int32_t gen_leech2_pair_type(uint64_t v1, uint64_t v2)
Isomorphsim type of pair of vectors in Leech lattice mod 2.
Let \(v_1\) and \(v_2\) be two vectors in the Leech lattice mod 2 and put \(v_3 = v_1 + v_2\). Let \(t_i, i = 1,2,3\) be the type of \(v_i\). Then the triple \((t_1, t_2, t_3)\) depends on the isomorphism type of the pair \((v_1, v_2)\).
If one or three of the vectors \((v_1, v_2, v_3)\) are of type 4 then there may be several isomorphism types of pairs \((v_1, v_2)\) with the same triple \((t_1, t_2, t_3)\). In this case we define a subtype \(s\) as follows. We map one of the vectors \(v_i\) of type 4 to the standard frame \(\Omega\). Let \(w\) be the image of any of the vectors \(v_j, j \neq i\) under any such mapping. Then we compute the subtype of \(w\) with function
gen_leech2_subtype
, and we let \(s\) be the last hexadecimal digit of the computed subtype. The result \(s\) does not depend on the choices made in the description given above.After reordering \(t_1, t_2, t_3\), the possibilties for tuples \((t_1, t_2, t_3, s)\) with a relevant component \(s\) are (4,2,2,0), (4,3,3,4), (4,3,3,6), (4,4,4,0), (4,4,4,4), (4,4,4,6).
If none of the vectors \((v_1, v_2, v_3)\) is of type 4 then all the shortest corresponding vectors in the Leech lattice are defined up to sign. Then these vectors may span a space of dimension 2 or 3; and we put \(s = 1\) if that dimension is equal to 3, and \(s = 0\) otherwise. The case \(s = 1\) may occur if and only if at least two of the vectors \((v_1, v_2, v_3)\) are of type 3 and none is of type 4.
In all other cases there is at most one such isomorphism type; and we put \(s = 0\).
The function takes \(v_1\) and \(v_2\) as parameters
v1
andv2
in Leech lattice encding. It returns\( 2^{12} \cdot t_1 + 2^8 \cdot t_2 + 2^4 \cdot t_3 + s .\)
We sketch a proof that the returned result actually describes the isomorphism type of the pair \((v_1, v_2)\). If one of the vectors \((v_1, v_2, v_3)\) is of type 4 then may map that vector to the standard frame \(\Omega\) and check the possible subtypes of the other vectors. These subtypes are described in subsection Computations in the Leech lattice modulo 2 of The guide for developers, or in
[Iva99]
, Section 4.4 ff.Otherwise the shortest preimages \(v'_1, v'_2, v'_3\) of \(v_1, v_2, v_3\) in the Leech lattice are defined up to sign. The cases where these preimages span a subspace of dimension 2 of the Leech lattice are well known, see e.g.
[CS99]
or[CCN+85]
. If \(v'_1, v'_2, v'_3\) span a 3-dimensional space, then it is easy to see that at least two of these vectors must be of type 3, and that all vectors \((v'_1 \pm v'_2 \pm v'_3)/2\) (with all possible combinations of signs) are in the Leech lattice and of type at most 3. The 3-dimensional lattices satifying these properties can be shown to be S-lattices, as defined in[CCN+85]
. Note that the S-lattices are also known.Warning: This function has not yet been tested!
C interface for file gen_leech_reduce_n.c
Given a vector \(v\) in the extraspecial group \(Q_{x0}\), the functions in this module compute a transformation from \(v\) to a standard representative of the class \(v^N\).
Here \(Q_{x0}\) and \(N = N_{x0}\) are as in the project documentation.
We use the terminology defined in the document The C interface of the mmgroup project, section Description of the mmgroup.generators extension.
Functions
-
int32_t gen_leech2_reduce_n(uint32_t v, uint32_t *pg_out)
Reduce Leech lattice vector modulo the group N_x0.
Given a vector \(v\) in the extraspecial group \(Q_{x0}\), we want to find a standard representative of the class \(v^N\), where \(Q_{x0}\) and \(N = N_{x0}\) are as in the project documentation. Here \(v\) is given in parameter
v
in Leech lattice encoding.This function computes such a representative \(v_1 \in Q_{x0}\). It returns an element \(r\) of \(N_{x0}\) with \(v_1 = v^r\) as a word of length three in the generators of \(N_{x0}\). That word is stored in the buffer referred by
pg_out
as an array of 3 integers of typeuint32_t
as described in section The monster group in the API reference.The user may call function
gen_leech2_op_word
in filegen_leech.c
for computing \(v_1 = v^r\). There is a faster alternative for computing \(v_1\) described in the documetnation of functiongen_leech2_reduce_n
.The representative \(v_1\) depends on the subtype of \(v\) only, with one exception listed below. Here the subtype can be also computed by function
gen_leech2_subtype
in filegen_leech.c
; it is explained in The mmgroup guide for developers in section Computations in the Leech lattice modulo 2.If the subtype of \(v\) is
00
then we have \(v_1 =v\) for the two vectors \(v = x_{\pm 1}\) of that subtype.We compute a mapping \(r = x_\pi y_e x_f\), where \(r\) is an automorphism of the Parker loop, \(e\) is in the Parker loop, and \(f\) is either in the Parker loop or in the Golay cocode.
The result \(r\) is in the even subgroup of \(N_{x0}\) except in case \(v = x_{-\Omega}\), where this is not possible.
See section Orbits of the group N_x0 in the group Q_x0 in The mmgroup guide for developers for our choice of the representative of the \(N_{x0}\) orbits.
-
int32_t gen_leech2_reduce_n_rep(uint32_t subtype)
Compute standard representative of Q_x0 modulo the group N_x0.
Given a subtype
subtype
in the Leech lattice modulo 2, the function returns a representative of a nonzero orbit of \(Q_{x0}\) under the action of \(N_{x0}\).See the table in section Orbits of the group N_x0 in the group Q_x0 in The mmgroup guide for developers for our choice of such a representative.
C interface for file gen_leech_reduce_22.c
Let \(\Lambda / 2\Lambda\) be the Leech lattice modulo 2. Let \(v_2, v_3 \in \Lambda / 2\Lambda\) with \(\mbox{type}(v_2) = 2\) and \(\mbox{type}(v_3) = \mbox{type}(v_2 + v_3) = t\) for \(2 \leq t \leq 3\). We want to compute the set of all vectors \(v_4 \in \Lambda / 2\Lambda\) of type 4 with \(\mbox{type}(v_2 + v_4) = \mbox{type}(v_3 + v_4) = \mbox{type}(v_2 + v_3 + v_4) = 2\). There are 891 or 100 such vectors in case \(t = 2\) or \(t = 3\), respectively. Function gen_leech2_u4_2xx
in this module computes the list of all such vectors.
We motivate this (rather complicated) computation as follows. The main algorithm for the reduction of an element of the Monster in Version v1.0.0 the mmgroup package works in the representation \(\rho_{15}\) of the monster, with coefficients taken mod 15. In future versions it would be faster to work in representation \(\rho_{3}\) instead. For the reduction algorithm we have to compute certain sets \(U_4(v)\) for axis \(v\) in the representation of the Monster as defined in [Sey22]. This computation is considerably more difficult for \(v \in \rho_3\) than for \(v \in \rho_{15}\). It turns out that for \(t = 2,3\) the sets computed above are just the sets \(U_4(v)\) when \(v\) is in the orbit called ‘6A’ or ‘10A’ in [Sey22]. Given an axis \(v \in \rho_3\) in one of these orbits, we can effectively compute suitable vectors \(v_2, v_3\) as discussed above.
For that computation we need a function that maps vectors \(v_2, v_3\) to fixed vectors \(w_2, w_{3t} \in \Lambda / 2\Lambda\). Function gen_leech2_reduce_2xx
essentially performs this task; see the documentation of that function for details.
The group fixing \(v_2\) and \(v_3\) is the unitary group \(\mbox{PSU}_6(2)\) in case \(t = 2\), and the Higman-Sims group in case \(t = 3\), see [CS99], Ch. 10.3.4. A detailed discussion of the case \(t = 3\) is given in [CS99], Ch. 10.3.5.
We use the terminology defined in the document The C interface of the mmgroup project, Section Description of the mmgroup.generators extension. Vectors in \(\Lambda / 2\Lambda\) are given in Leech lattice encoding; the sign bit is ignored on input and set to zero on output.
Functions
-
int32_t gen_leech2_n_type_22(uint32_t n)
Generate certain type-2 vectors in the Leech lattice.
The function maps the integers \( 0 \leq n < 4600\) to the 4600 type-2 vectors \(v\) in the Leech lattice mod 2, such that that \(v+w\) is also of type 2 in the Leech lattice mod 2. Here \(w\) is the standard type-2 vector \((0, 0, 4, -4, 0, \ldots, 0)\). Such a vector \(v\) is returned in Leech lattice encoding.
The function returns a negative value in case of failure; e.g. if \(n \geq 4600\).
-
int32_t gen_leech2_find_v4_2xx(uint32_t v2, uint32_t v3, uint64_t *seed)
Support for reducing a certain pair of vectors in the Leech lattice.
Let
v2
be a vector of type 2 in the Leech lattice mod 2, and letv3
be a vector of type t in the Leech lattice mod 2, with 2 <= t <= 3, such thatv2 + v3
is also of type t. Herev2
andv3
must be given in Leech lattice encoding.The function computes a vector
v4
of type 4 such thatv2 + v4, v3 + v4
, andv2 + v3 + v4
are all of type 2. Vectorv4
can be used in functiongen_leech2_find_v4_2xx
for reducing the pair(v2, v3)
to a standard pair of vectors.The function returns the value
t * 0x1000000 + v4
in case of succcess, with t as above. Parameterseed
is a seed for a random generator as described in modulegen_random.c
. The function returns a negative value in case of failure.The function tries to find random vectors
vx
of type 2 in the Leech lattice mod 2 such that both,vx + v2
, andvx + v3
are of type 2. Then the vectorv4 = v2 + v3 + vx
satifies the required conditions.For finding
vx
we transformv2
to the standard type-2 vector with a transformationtf
. Then we generate random type-2 vectors with functiongen_leech2_n_type_22
. These random type-2 vectors are interpreted as transformed vectorstf(vx)
; and we will check the required conditions on the transformed vectorstf(v2)
,tf(v3)
, andtf(vx)
.
-
int32_t gen_leech2_reduce_2xx(uint32_t v2, uint32_t v3, uint32_t v4, uint32_t *g)
Reduce a certain pair of vectors in the Leech lattice.
Let
v2
be a vector of type 2 in the Leech lattice mod 2, and letv3
be a vector of type t in the Leech lattice mod 2, with 2 <= t <= 3, such thatv2 + v3
is also of type t. Herev2
andv3
must be given in Leech lattice encoding.The function computes an element
g
of the Conway group \(\mbox{Co}_1\) such thatv2 * g = w2
andv3 * g = w3
withw2 = (0, 0, 4, -4, 0, ..., 0)
. Here we havew3 = (0, 4, -4, 0, ..., 0)
ift == 2
andw3 = (1, 1, 5, 1, ..., 1)
ift == 3
.The function stores
g
in the arrayg
as a word of lengthk
of generators of the subgroupG_x0
of the Monster. These generators are encoded as described in filemmgroup_generators.h
. We havek <= 8
; so the arrayg
must have size at least 8.The function returns the value
k >= 0
in case of succcess, and a negative value in case of failure.Parameter
v4
must be a type-4 vector satisfying certain conditions as described in de documentation of functiongen_leech2_find_v4_2xx
. That function computes a suitable random vectorv4
.Internally, we use function
gen_leech2_reduce_type4
to find an elementg_0
of \(\mbox{Co}_1\) that mapsv4
to the standard type-4 vectorOmega
. To finish up, we just have to calculate an elementg_1
of the subgroup \(2^{11}.M_{24}\) of \(\mbox{Co}_1\) such thatg = g_0 * g_1
satisfies the required conditions.
-
int32_t gen_leech2_map_2xx(uint32_t *g, uint32_t n, uint32_t t, uint32_t *a)
Auxiliary function for function
gen_leech2_u4_2xx
Let
v2
,v3
be as in functiongen_leech2_reduce_2xx
. Letg
be an element of the groupG_x0
of lengthn
that mapsv2
andv3
tow2
andw3
, withw2
,w3
as in functiongen_leech2_reduce_2xx
. Hereg
should have been computed by that function.The function computes all vectors
v4
of type 4 in the Leech lattice mod 2 such thatv2 + v4, v3 + v4
, andv2 + v3 + v4
are of type 2. It stores the list of these vectors in the arraya
and returns the length of that list.Array
a
must have length 891 in caset == 2
and length 100 in caset == 3
. Other values oft
are illegal.
-
int32_t gen_leech2_u4_2xx(uint32_t v2, uint32_t v3, uint64_t *seed, uint32_t *a)
Compute a certain set of type-4 vectors in the Leech lattice mod 2.
Let
v2
be a vector of type 2 in the Leech lattice mod 2, and letv3
be a vector of type t in the Leech lattice mod 2, with 2 <= t <= 3, such thatv2 + v3
is also of type t. Herev2
andv3
must be given in Leech lattice encoding.The function computes all vectors
v4
of type 4 in the Leech lattice mod 2 such thatv2 + v4, v3 + v4
, andv2 + v3 + v4
are of type 2. There are 891 such vectors in caset = 2
and 100 such vectors in caset = 3
. The list all these vectors is stored in the arraya
in Leech lattice encoding in an undefined order. Thus arraya
must have length at least 891.The function uses a random generator. Parameter
seed
is a seed for a random generator as described in modulegen_random.c
.The function returns the length of the array
a
in case of succcess, and a negative value in case of failure.
C interface for file gen_union_find.c
The functions in file gen_union_find.c
implement a union-find algorithm. This may be used e.g. for computing the orbits of the Leech lattice mod 2 under the action of a group.
Functions
-
int32_t gen_ufind_init(uint32_t *table, uint32_t length)
Initialize table for union-find algorithm.
The function initializes an array referred by parameter
table
for performing a union-find algorithm on the setS(length)
of integersi
with0 <= i < length
. Arraytable
must have sizelength
. Here0 <= length <= 0x40000000
must hold.Then
table
will store a partition of the setS(length)
in an internal format. Initially, that partition consists of singletons. One may use functiongen_ufind_union
for joining two sets of that partition. Any set in the partition is represented by an element of that set. The rules for computing a representative of a set are not disclosed to the user. You may use functiongen_ufind_find
for finding the representative of a set. After calling functiongen_ufind_find_all_min
each set is represented by its smallest element. The representative of a set may change after calling functiongen_ufind_union
.The function returns 0 in case of success, and a negative value in case of failure (e.g. if
length
is too big.)
-
int32_t gen_ufind_find(uint32_t *table, uint32_t length, uint32_t n)
The find function for the union-find algorithm.
Let
S(length)
be the set of integersi
with0 <= i < length
; and let a partition ofS(length)
be stored in the arraytable
(of sizelength
) as described in functiongen_ufind_init
.The function returns the representative of the set containing the integer
n
. It returns a negative number in case of failure, e.g. ifn >= length
.
-
void gen_ufind_union(uint32_t *table, uint32_t length, uint32_t n1, uint32_t n2)
The union function for the union-find algorithm.
Let
S(length)
be the set of integersi
with0 <= i < length
; and let a partition ofS(length)
be stored in the arraytable
(of sizelength
) as described in functiongen_ufind_init
.The function joins the sets in the partition containg the elements
n1
andn2
.
-
int32_t gen_ufind_find_all_min(uint32_t *table, uint32_t length)
Choose smallest representatives for sets in union-find algorithm.
Let
S(length)
be the set of integersi
with0 <= i < length
; and let a partition ofS(length)
be stored in the arraytable
(of sizelength
) as described in functiongen_ufind_init
.The function chooses the smallest element of a set in a partition as the representative of the set. Thus a subsequent call to function
gen_ufind_find
with parametern
returns the smallest element of the set containgn
.The function returns the number of the sets in the partition. A negative return value indicates a error the array
table
.
-
int32_t gen_ufind_partition(uint32_t *table, uint32_t length, uint32_t *ind, uint32_t len_ind)
Output the partition computed by the union-find algorithm.
Let
S(length)
be the set of integersi
with0 <= i < length
; and let a partition ofS(length)
be stored in the arraytable
(of sizelength
) as described in functiongen_ufind_init
.We assume that the partition stored in the array
table
containsn_sets
sets. Then we overwrite the arraytable
with a list of lists, where each list corresponds to a set in the partition. We write some index infomation for interpreting these lists into the arrayind
of lengthlen_ind
.Array
table
will contain thelength
elements of the setS(length)
in such a way that for0 <= i < n_sets
thei
-th set in the partition is equal to the set of integers given bytable[ind[i]], ..., table[ind[i+1] - 1]
.So the array
ind
must have size at leastn_sets + 1
; i.e. we must havelen_ind > n_sets
. Functiongen_ufind_find_all_min
must be called beford calling this function. Note that functiongen_ufind_find_all_min
returnsn_sets
in case of success.The entries
table[ind[i]], ..., table[ind[i+1] - 1]
corresponding to set in the partition are sorted. The sets of the partition are sorted by their smallest elements.The function returns
n_set
in case of success and a negative value in case of failure.
-
void gen_ufind_union_affine(uint32_t *table, uint32_t length, uint32_t *m, uint32_t len_m, uint32_t v)
Perform affine union operations in the union-find algorithm.
Let
S(length)
be the set of integersi
with0 <= i < length
; and let a partition ofS(length)
be stored in the arraytable
(of sizelength
) as described in functiongen_ufind_init
.In this function the entries of
S(length)
are interpreted as bit vectors. The function joins the set containingi
with the set containgi * M + v
for alli
. HereM
the bit matrix over GF(2) referred bym
withlen_m
rows, andv
a bit vector. All bit vector arithmetic is done over GF(2).
-
int32_t gen_ufind_union_leech2(uint32_t *table, uint32_t *g, uint32_t len_g)
Join orbits of the Leech lattice mod 2.
The Conway group \(\mbox{Co}_1\) has a natural action on on \(\Lambda / 2 \Lambda\), i.e. on the Leech lattice mod 2. The subgroup \(G_{x0}\) of the Monster (of structure \(2^{1+24}.\mbox{Co}_1\)) has the same action on on \(\Lambda / 2 \Lambda\).
In this function we assume that the array
table
contains a partition of the set \(\{i \mid 0 \leq i < 2^{24}\}\) as described in functiongen_ufind_init
. In that function the arraytable
should have been initialized with a length of \(2^{24}\).Here each integer \(i\) is interpreted as an element of \(\Lambda / 2 \Lambda\) in Leech lattice encoding, as described in the document The C interface of the mmgroup project, section Description of the mmgroup.generators extension.
Let \(g \in G_{x0}\) be stored in the array referred by
g
as a word of generators of the subgroup \(G_{x0}\) of the monster. Here \(g\) is given as a word of generators of lengthlen_g
in the arrayg
. Each atom of the word \(g\) is encoded as defined in the header filemmgroup_generators.h
.Then the function joins the set containing \(i\) with the set containing \(i \cdot g\) for all \(i\), using the union-find algorithm.
The function returns 0 in case of success and a negative value in case of failure (e.g. if \(g\) is not in \(G_{x0}\)).
C functions for the generator \(\xi\) of the monster group
The functions in module gen_xi_functions.c
deal with the
operation of the generator \(\xi\) of the monster defined
in [Sey20], section 9, on a subgroup \(Q_{x0}\) and
also with the monomial part of that operation on the
196884-dimensional representation \(\rho\) of the monster.
Generator \(\xi\) is an element of the subgroup \(G_{x0}\) of the monster. \(G_{x0}\) operates on its normal subgroup \(Q_{x0}\) of of structure \(2^{1+24}\) by conjugation as described in the Guide, section Computations in the Leech lattice modulo 2. \(Q_{x0}\) is extraspecial and has center \(\{\pm1\}\). We have \(Q_{x0} / \{\pm 1\} \cong \Lambda / 2 \Lambda\). An element \(x\) of \(Q_{x0}\) is short if it corresponds to a vector in the Leech lattice \(\Lambda\) of norm 4. \(G_{x0}\) also operates on the \(2 \cdot 98280\) short elements of \(Q_{x0}\).
Representation \(\rho\) has a subspace \(98280_x\) of dimension 98280 on which \(G_{x0}\) operates monomially in the same way as it operates on the short elements of \(Q_{x0}\). So the basis vectors of \(98280_x\) (together with their opposite vectors) can be identified with the short elements of \(Q_{x0}\).
The functions in module gen_xi_functions.c
are also used for
computing tables describing the monomial operation of
\(\xi^e, e=1,2\) on \(98280_x\).
Module mmgroup.dev.generators.gen_xi_ref
is a pure python
substitute for this set of C functions; but calculating the tables
with python takes a rather long time.
In section The representation of the Monster group we use the following names and tags for the basis vectors of \(98280_x\).
Name
Tag
Entries
Remarks
\(X^+_{ij}\)
B
i, j; 0 <= j < i < 24
\(X_{ij}\)
C
i, j; 0 <= j < i < 24
\(X_{o,s}\)
T
o, s; 0 <= o < 759, 0 <= s < 64
\(X_{d,j}\)
X
d, j; 0 <= d < 2**11, 0 <= j < 24
(1),(3)
Remarks
i and j, 0 <= i,j < 24 refer to basis vectors of the Boolean vector space in which the Golay code is defined.
o is one of 759 octads, s is one of 64 even subsets of octad d (modulo its complement in d), as described in section Octads and suboctads.
d with 0 <= d < 2048 refers to the Parker loop element d. For larger values d we have:
\[ \begin{align}\begin{aligned}X_{2048+k,j} = X_{k,j}, \; Y_{2048+k,j} = -Y_{k,j}, \; Z_{2048+k,j} = Z_{k,j},\\U_{4096+k,j} = -U_{k,j}, \quad \mbox{for} \; U = X, Y, Z; \; 0 <= k < 2048 \, .\end{aligned}\end{align} \]
We group these basis vectrors into 5 boxes (labelled 1,…,5) with each box containing at most \(3 \cdot 2^{13}\) entries. Element \(\xi\) permutes these boxes as follows:
Box1 -> Box1, Box2 -> Box2, Box3 -> Box4 -> Box5 -> Box3 . (1)
The mapping from the basis vectors to entries in boxes is:
Basis vector
Box
Entry
B[i,j]
1
0 + 32 * i + j
C[i,j]
1
768 + 32 * i + j
T[o,s], o < 15
1
1536 + 64 * o + j
T[o,s], 15 <= o < 375
2
64 * (o - 15) + j
T[o,s], o >= 375
3
64 * (o - 375) + j
X[d,j], d < 1024
4
32 * d + j
X[d,j], d >= 1024
5
32 * (d - 1024) + j
This subdivision looks weird, but is has quite a few advantages:
The lower index (j or s) has stride 1, and the the stride of the higher index (i, o or d) is the lowest possible power of two. So accessing an entry is easy. In the C code for a representation derived from \(\rho\) the entries of a vector of such a representation are strided in the same way. So the tables computed in this module can be used in the C code for operator \(\xi\).
An entry in a box is always less than \(2^{15}\), so any entry can be stored in a 16-bit integer, together with a sign bit.
Boxes are permuted as above, so 4 tables of 16-bit integers and size <= \(3 \cdot 2^{15}\) are sufficent to encode the operation of \(\xi\).
We remark that boxes 3 and 5 contain the short vectors with odd Golay code words; the other boxes contain those with even code words. Here the parity (even/odd) of a Golay code word means the scalar product with the cocode word \(\omega\) which has six 1-bits in column 0 of the MOG, see [Sey20], section 2.2. Short vectors with an odd cocode element occur precisely in boxes 4 and 5.
A similar, but finer subdivision of the whole space \(\rho\) (and not only of the subspace \(98280_x\)) is given in [Iva09], section 3.4.
The operation of the generator \(\xi\) on the group \(Q_{x0}\)
Using [Sey20], Lemma 9.5, we can easily compute the values \(\xi^{-e} x \xi^e\) for all short \(x \in Q_{x0}\) and \(e = 1,2\). Here we represent an \(x \in Q_{x0}\) as a 25-bit integer in Leech lattice encoding as described above.
Let \(\mathcal{C}\) and \(\mathcal{C}^*\) be the Golay code and its cocode. In [Sey20], section 2.2 we give decompositions \(\mathcal{C} = \mathcal{G} \oplus \mathcal{H}\) and \(\mathcal{C}^* = \mathcal{G}^* \oplus \mathcal{H}^*\).
The formulas in ibid., Lemma 9.5 use auxiliary functions \(\gamma : \mathcal{G} \rightarrow \mathcal{G^*}\) and \(w_2 : \mathcal{G} \cup \mathcal{G^*} \rightarrow \mathbb{F}_2\) defined in ibid., section 3.3. Using the decompositions above, we may extend \(\gamma\) to \(\mathcal{C}\) and \(w_2\) to \(\mathcal{C} \cup \mathcal{C^*}\).
Short vector encoding of the short vectors in \(Q_{x0}\)
For each short vector in \(Q_{x0}\) we compute the number of the box and the entry in the box using the information given in (2). Then we store the vector in the lowest 19 bits of a 32-bit integer as follows:
Bit 18…16: number of the box
Bit 15: sign bit
Bit 14…0: Entry in the box
Tables for the operation of \(\xi\) and \(\xi^2\) contain the lower 16 bits of that encoding. Bits 18…16 can be reconstructed from the permutation of the boxes given by (1).
We precomute a set of tables containing \(2 \cdot 98260\) values \(\xi^{-e} x \xi^e\), where the short element \(x\) of \(Q_{x0}\) is given in Short vector encoding.
C interface for file gen_xi_functions.c
The functions in file gen_xi_function.c
implement the operation of the generator \(\xi\) on the group \(Q_{x0}\).
Functions
-
uint32_t gen_xi_g_gray(uint32_t v)
Compute function \(\gamma\) on a Golay code element.
Here parameter \(v\) is encoded in
gcode
representation, and the return value \(\gamma(v)\) is encoded incocode
representation. These representations are defined in the Description of the mmgroup.mat24 extension.
-
uint32_t gen_xi_w2_gray(uint32_t v)
Compute function \(w_2\) on a Golay code element.
Here parameter \(v\) is encoded in
gcode
representation as defined in the Description of the mmgroup.mat24 extension. The function returns \(w_2(v)\), which may be 0 or 1.
-
uint32_t gen_xi_g_cocode(uint32_t c)
A kind of an inverse of function \(\gamma\).
Given a cocode element \(c\) in
cocode
representation, the function returns the unique grey Golay code vector \(v\) such that \(\gamma(v)\) is equal to the grey part of \(c\). \(v\) is returned ingcode
representation, see the Description of the mmgroup.mat24 extension.
-
uint32_t gen_xi_w2_cocode(uint32_t v)
Compute function \(w_2\) on a Golay cocode element.
Here parameter \(v\) is encoded in
cocode
representation as defined in the Description of the mmgroup.mat24 extension. The function returns \(w_2(v)\), which may be 0 or 1.
-
uint32_t gen_xi_op_xi(uint32_t x, uint32_t e)
Conjugate an element of the group \(Q_{x0}\) with \(\xi^e\).
The function returns \(\xi^{-e} x \xi^e\) for an element \(x\) of the group \(Q_{x0}\). Input \(x\) and the return value are encoded in Leech lattice encoding as described above.
-
uint32_t gen_xi_op_xi_nosign(uint32_t x, uint32_t e)
Similar to function
gen_xi_op_xi
, ingoring sign.The function returns \(\xi^{-e} x \xi^e\) for an element \(x\) of the group \(Q_{x0}\). Input \(x\) and the return value are encoded in Leech lattice encoding as described above. This function computes the result up to sign only.
-
uint32_t gen_xi_leech_to_short(uint32_t x)
Convert the encoding of an element of the group \(Q_{x0}\).
The function converts an element \(x\) of the group \(Q_{x0}\) from Leech lattice encoding to Short vector encoding and returns the converted element.
-
uint32_t gen_xi_short_to_leech(uint32_t x)
Convert the encoding of an element of the group \(Q_{x0}\).
The function converts an element \(x\) of the group \(Q_{x0}\) from Short vector encoding to Leech lattice encoding and returns the converted element.
An invalid value \(x\) is converted to 0.
-
uint32_t gen_xi_op_xi_short(uint32_t x, uint32_t u)
Conjugate an element of the group \(Q_{x0}\) with \(\xi^e\).
The function returns \(\xi^{-e} x \xi^e\) for an element \(x\) of the group \(Q_{x0}\). In contrast to function gen_xi_op_xi, the input \(x\) and the return value are encoded in short vector encoding as described above.
Any invalid element \(x\) is converted to \(x\).
-
uint32_t gen_xi_make_table(uint32_t b, uint32_t e, uint16_t *ptab)
Create table for operation of \(\xi^e\),.
The function creates a table
ptab
such thatptab[i]
encodes \(\xi^{-e} x \xi^e\), where \(x = 2^{16} \cdot b + i\) encodes a short vector in \(Q_{x0}\) in Short vector encoding. The length of the gererated table is \(l(b) = 2496, 23040, 24576, 32768, 32768\) for \(b = 1,2,3,4,5\).Here
ptab[i]
contains the lower 16 bits of the table entry only, with bit 15 equal to the sign bit. The upper 3 bits ofptab[i]
depend onb
only; they can be deduced from the permutation of the boxesb = 1,...,5
by \(\xi\) described above.Not all table indices
i
correspond to short vectors. We putp[i] = i
for all invalid indicesi
.
-
void gen_xi_invert_table(uint16_t *ptab, uint32_t len, uint32_t ncols, uint16_t *pres, uint32_t len_res)
Invert a table created by function
gen_xi_make_table
The function computes the inverse table of a table
ptab
of lengthlen
created by functiongen_xi_make_table
and stores the inverse table in the buffer referred bypres
.Parameter
len_res
is the length of the returned table. Parameterncols
must be 24 or 32. This means that only entriesptab[32*i + j]
with0 <= j < ncols
are valid.The details of the inversion of such a table are rather tricky; they are coded in class
mmgroup.dev.mm_basics.mm_tables_xi.Pre_MM_TablesXi
. The purpose of this function is to speed up the calculations in that class.
-
void gen_xi_split_table(uint16_t *ptab, uint32_t len, uint32_t mod, uint32_t *psign)
Split a table created by function
gen_xi_invert_table
The function splits the sign bit from a table
ptab
of lengthlen
created by functiongen_xi_invert_table
and replacesptab[i]
by(ptab[i] & 0x7fff) % mod
. The sign bitptab[32*i+j] >> 15
is stored in bitj
of entrypsign[i]
.The purpose of this function is to speed up the computations in class
mmgroup.dev.mm_basics.mm_tables_xi.Pre_MM_TablesXi
.
C functions implementing a random generator
The python extension mmgroup.generators
provides a random
generator. Its main purpose is the very fast generation of
a vector of integers modulo \(p\) for the representation
\(\rho_p\) of the monster group for small numbers \(p\).
The internal operation of the random generator is described in
file gen_random.c
. Here we describe the python interface
of the random generator.
This interface is given by a set of functions that can be
imported from python module mmgroup.generators
.
A python function dealing with the randon generator requires
a seed. Here a seed is either an object returned by function
rand_make_seed
or None
(default).
The default seed is (hopefully) thread save, and it is initialized from volatile sources such as the time, the process and the thread id, etc.
A seed created by function rand_make_seed
is initalized
from a fixed source (which is a 64-bit integer).
Each seed may be used by one thread only. In python a seed is crreated for each thread whenever needed.
Python functions in module mmgroup.generators
The following functions should be imported from
module mmgroup.generators
.
- .rand_get_seed()
Return the seed associated with the current thread
This function is used for obtaining a suitable python object for calling a C function that deals with the random generator. The user must not modify that seed!
- .rand_make_seed(valu)
Create a deterministic seed object for the random generator
The function creates a seed object and returns that object. It is intialized with parameter
value
, which must be an unsigned 64-bit integer.
- .rand_bytes_modp(p, num_bytes, seed=None)
Return a random array of integers mod p
The function returns a one-dimensional numpy array of uniform distributed random integers
x
with0 <= x < p
. That array has lengthnum_bytes
and hasdtype = numpy.uint8
.Parameter
seed
must be eitherNone
(default, referring to the default seed) or a seed object created by functionrand_make_seed
.
- .rand_fill_bytes_modp(p, array_bytes, seed=None)
Fill an existing array with random integers mod p
The function fills the one-dimensional numpy array
array_bytes
with uniform distributed random integersx
with0 <= x < p
. That array must havedtype = numpy.uint8
.Parameter
seed
must be eitherNone
(default, referring to the default seed) or a seed object created by functionrand_make_seed
.
- .rand_gen_modp(p, seed=None)
Return random integer
x
with0 <= x < p
.Here 1 <= p <= 2**32 must hold.
Parameter
seed
must be eitherNone
(default, referring to the default seed) or a seed object created by functionrand_make_seed
.
C interface for file gen_random.c
File gen_random.c
provides a fast random generator for creating random vectors in the representations of the monster group. This generator supports very fast generation of long random vectors of integers modulo p
for p <= 256
.
The seed for such a random generator is given by an array of type uint64_t seed[MM_GEN_RNG_SIZE]
. In this version we have MM_GEN_RNG_SIZE = 4
.
The function gen_rng_seed(uint64_t *seed)
fills an existing array seed
of that type with random seed data. See description of that function for details. The idea is that in a mulithreading environment every thread has its own random generator. There is also a function gen_rng_seed_no
for a determistic intialization of the seed
. The user should call function gen_rng_seed_init
for initialization.
The function gen_rng_bytes_modp(uint32_t p, uint8_t *out, uint32_t len, uint64_t *seed)
writes len
uniform random numbers x_i
with 0 <= x_i < p
to the array referred by the pointer out
. Here 1 < p <= 256
must hold.
This function is optimized for generating large random vectors with, say, len >= 1000
, as required for the representation of the monster.
Function gen_rng_modp
generates a single random number x
with 0 <= x < p
for a 32-bit number p
.
Internal operation.
We use the xoshiro256** pseudo random number generator, see
https://bashtage.github.io/randomgen/bit_generators/xoshiro256.html
We seed a master generator from various external random sources, e.g. the system time, the process id, etc. We use xoshiro256** for both, the master and the user generator. We shift the master generator by 2**128 steps for seeding a user generator.
Functions
-
void gen_rng_seed_init(void)
Seed the master random generator with random data.
Here
seed
is an array of 4 integers of typeuint64_t
.The function fills the
seed
with random data, using various sources, e.g. the system time, the process id, etc.
-
void gen_rng_seed_no(uint64_t *seed, uint64_t seed_no)
Seed a user random generator deterministically.
Here
seed
is an array of 4 integers of typeuint64_t
.The function fills the
seed
with data depending on the numberseed_no
.
-
void gen_rng_seed(uint64_t *seed)
Seed a user random generator from the master random generator.
Here
seed
is an array of 4 integers of typeuint64_t
.The function seeds the user generator with the seed
seed
from the master random generator. The function is thread-safe if functiongen_rng_seed_init()
has been called before.Each thread must use its own seed.
-
int32_t gen_rng_bytes_modp(uint32_t p, uint8_t *out, uint32_t len, uint64_t *seed)
Generate random integers modulo a small number
p
Generate an array of length
len
of random 8-bit integersx
with0 <= x < p
. Here1 < p <= 256
must hold.These random integers are written to the array referred by
out
.Parameter
seed
points to the seed for the random generator. That seed must have been created by functiongen_rng_seed_rnd
` or by a similar function.The function returns zero in case of success and a nonzero value otherwise.
-
uint32_t gen_rng_modp(uint32_t p, uint64_t *seed)
Generate one random integer modulo a number
p
Generate an integer
x
with0 <= x < p
. Here0 <= p < 2**32
must hold.p = 0
is interpreted asp = 2**32
.Parameter
seed
points to the seed for the random generator. That seed must have been created by functiongen_rng_seed_rnd
or by a similar function.The function returns the random number
x
.
-
uint64_t gen_rng_bitfields_modp(uint64_t p, uint32_t d, uint64_t *seed)
Generate random bit field of integers modulo a number
p
Generate integers
x_i
,0 <= i < 64 / d
with0 <= x < p
. Here parameterd
is the with of a bit field. The function reuturns an unsigned 64-bit integerx
with the random valuex_i
stored in bitsi*d + d - 1,..., i *d
ofx
. In cased = 0
we generate one random number inx
.Here
1 <= p < 2**d
must hold.p = 0
is interpreted asp = 2**64
.Parameter
seed
points to the seed for the random generator. That seed must have been created by functiongen_rng_seed_rnd
or by a similar function.
Description of the mmgroup.clifford12
extension
Quadratic state vectors
The C functions in modules qstate.c
and qsmatrix.c
perform
operations on quadratic state matrices given by triples
\((e, A, Q)\) as described in API reference the section
The subgroup G_{x0} of the Monster and the Clifford group.
A quadratic state vector \(v\) of type
qbstate12_type
with component ncols = n
models a complex
vector in a vector space \(V\) of dimension \(2^n\),
or an \(2^{n-k} \times 2^k\) matrix.
The basis of vector space \(V\) is labelled by the elements of the Boolean vector space \(\mathbb{F}_2^n\). In C and python programs we represent the element \((x_{n-1}, \ldots, x_{0})\) of \(\mathbb{F}_2^n\) by the integer \(\sum_{0 \leq i < n} 2^i \cdot x_i\). This leads to a natural representation of a vector \(v \in V\) as a one-dimensional complex array of length \(2^n\), starting with index \(0\).
A quadratic state matrix is a quadratic shape vector augmented
by an information about its matrix shape. For more details we
refer to the description of struct qbstate12_type
in file
clifford12.h
.
Header file clifford12.h
File
clifford.h
is the header file for shared librarymmgroup_clifford12
. This comprises the following C modules:{0}.
Defines
- QSTATE12_UNDEF_ROW
Marker for an undefined row index in function qstate12_row_table()
Enums
- enum qstate12_error_type
Error codes for functions in this module.
Unless otherwise stated, the functions in modules
qstate.c
,qmatrix.c
, andxsp2co1.c
return nonnegative in case of success and negative values in case of failure. Negative return values mean error codes as follows:Values:
- enumerator ERR_QSTATE12_NOTFOUND
No object with the requested property found.
- enumerator ERR_QSTATE12_INCONSISTENT
State is inconsistent.
- enumerator ERR_QSTATE12_QUBIT_INDEX
Qubit index error.
- enumerator ERR_QSTATE12_TOOLARGE
State is too large for this module.
- enumerator ERR_QSTATE12_BUFFER_OVFL
Buffer overflow; usually there are now enough rows available.
- enumerator ERR_QSTATE12_Q_NOT_SYMM
Bit matrix part Q is not symmetric.
- enumerator ERR_QSTATE12_BAD_ROW
Bad row index for bit matrix.
- enumerator ERR_QSTATE12_INTERN_PAR
Internal parameter error. Usually a bad row has been requested.
- enumerator ERR_QSTATE12_SCALAR_OVFL
Overflow or underflow in scalar factor.
- enumerator ERR_QSTATE12_CTRL_NOT
Bad control_not gate. A qubit in a ctrl-not gate cannot control itself.
- enumerator ERR_QSTATE12_SHAPE_COMP
Shape mismatch in comparing matrices.
- enumerator ERR_QSTATE12_SCALAR_INT
Scalar factor is not an integer.
- enumerator ERR_QSTATE12_PARAM
Parameter error.
- enumerator ERR_QSTATE12_DOMAIN
Matrix is not is the expected domain.
- enumerator ERR_QSTATE12_SHAPE_OP
Shape mismatch in matrix operation.
- enumerator ERR_QSTATE12_MATRIX_INV
Matrix is not invertible.
- enumerator ERR_QSTATE12_PAULI_GROUP
Matrix is not in the Pauli group.
- enumerator ERR_QSTATE12_NOT_MONOMIAL
Matrix is not monomial.
- enumerator ERR_QSTATE12_LEECH_OP
Internal error in operation of group Co_0.
- enumerator ERR_QSTATE12_REP_GX0
Error in operation of group 2^{1+24}.Co_1.
- enumerator ERR_QSTATE12_NOTIN_XSP
Element of G_x0 not in 2^{1+24}.
- enumerator ERR_QSTATE12_GX0_TAG
Bad tag for atom in group G_x0.
- enumerator ERR_QSTATE12_GX0_BAD_ELEM
Bad element of group G_x0.
- struct qstate12_type
#include <clifford12.h>Description of a quadratic state matrix.
More precisely, a variable of this type decribes the representation \((e', A, Q)\) of a quadratic mapping \(f(e', A, Q)\). Here \(A\) is an \((1+m) \times n\) bit matrix. \(Q\) is a symmetric \((1+m) \times (1+m)\) bit matrix representing an symmetric bilinear form. We always have \(Q_{0,0}=0\). Then the quadratic mapping \(f(e', A, Q): \mathbb{F}_2^n \rightarrow \mathbb{C} \) is given by
\[ f(e',A,Q)(x) = e' \cdot \sum_{{\{{y = (y_0,\ldots,y_m) \in \mathbb{F}_2^{m+1} \mid y_0 = 1, y \cdot A = x\}}}} \exp \left( \frac {\pi \sqrt{{-1}}}{2} \sum_{j,k=0}^m Q_{j,k} y_j y_k \right) \, . \]Matrices \(A\) and \(Q\) are concatenated to an \( (m+1) \times (n+m+1)\) matrix \(M\) such that \(M_{i,j} = A_{i,j}\) for \(j < n\) and \(M_{i,j} = Q_{i-n,j}\) for \(j \geq n\). Matrix \(M\) is encoded in a one-dimensional array of unsigned 64-bit integers. Here bit \(j\) of entry \(i\) of the array corresponds to \(M_{i,j}\), with bit \(0\) the least significant bit.
We do not update column \(0\) of matrix \(Q\). \(Q_{j,0}\) is inferred from \(Q_{0,j}\) for \(j>0\) and we always have \(Q_{0,0} = 0.\)
We also interpret a quadratic mapping \( f \) from \(\mathbb{F}_2^n\) to \(\mathbb{C}\) as a complex \(2^{n-k} \times 2^k\) matrix \(U\) with entries \(U[i,j] = f(b_0,\ldots,b_{n-1})\), where \((b_{n-1},...,b_0)_2\), is the binary representation of the integer \(i \cdot 2^k + j\), and \(k\) is given by component
shape1
of the structure.The current implementation requires \(n + m <= 63\), so that all columns of the bit matrix \(M\) fit into a 64-bit integer. With this restriction we may still multiply \(2^{12} \times 2^{12}\) matrices \(U\) given as quadratic mappings.
A quadratic mapping may be reduced with function qstate12_reduce() without notice, whenever appropriate.
Warning:
If an external function changes any component of a structure
qs
of typeqstate12_type
(or the content ofqs.data
) then it must setqs.reduced
to zero. The onlylegal way to
set
qs.reduced
to a nonzero value is to call functionqstate12_reduce
. The functions in this module assume thatqs
is actually reduced ifqs.reduced
is not zero.Public Members
- uint32_t maxrows
No of entries of type
uint64_t
allocated to componentdata
- uint32_t nrows
No \(m + 1\) of rows of bit matrix \(A\) The value
nrows = 0
encodes the zero mapping.
- uint32_t ncols
No \(n\) of columns of bit matrices \(A\) and \(Q\).
- int32_t factor
A integer \(e\) encoding the complex scalar factor \(e'=\) \(\exp(e \pi \sqrt{-1}/4) \cdot 2^{\lfloor e/16 \rfloor / 2}\)
- uint32_t shape1
Describes the shape of the quadratic state matrix as explained above.
- uint32_t reduced
This is set to 1 if the state is reduced and to 0 otherwise.
- uint64_t *data
Pointer to the data bits of the matrix \(M = (A,Q)\).
C functions in bitmatrix64.c
File
bitmatrix64.c
contains functions for computing with bit matrices. A bit matrix of up to 64 columns is stored in an array of integers of typeuint64_t
. If matrixm
is stored in the arraya
then entrym[i,j]
is given by bitj
of the entrya[i]
of the arraya
. Here bitj
has valence \(2^j\).In functions dealing with bit matrices we always give the number of rows as a parameter. In some functions we also give the number of columns. In other functions we assume that there are 64 columns, with unused columns ignored.
Functions
- uint32_t uint64_parity(uint64_t v)
Returns the parity of a 64-bit integer
v
.
- uint32_t uint64_low_bit(uint64_t v)
Returns position of lowest bit of a 64-bit integer
v
.In case
v = 0
the function returns 64.
- uint32_t uint64_bit_len(uint64_t v)
Returns the bit length of a 64-bit integer
v
.
- uint32_t uint64_bit_weight(uint64_t v)
Returns the bit weight of a 64-bit integer
v
.
- uint32_t uint64_to_bitarray(uint64_t v, uint8_t *bl)
Convert 64-bit integer
v
to a bit list.Return the (sorted) array
bl
of the positions of all bits set in the integerv
. The function returns the length of the computed array, which is equal to the bit weight ofv
. Arraybl
should have length at least 64. The function is optimized for integersv
of low bit weight.
- void bitmatrix64_add_diag(uint64_t *m, uint32_t i, uint32_t j)
Add a diagonal matrix to a bit matrix.
Here bit matrix
m
hasi
rows.We add one to all entries
m[k, j+k]
for0 <= k < i
`.
- void bitmatrix64_mask_rows(uint64_t *m, uint32_t i, uint64_t mask)
Mask rows of a bit matrix.
Here bit matrix
m
hasi
rows.We replace all rows
m[k]
ofm
bym[k] & mask
. So we zero the entriesm[i,j]
for allj
where bitj
is zero in parametermask
.
- int32_t bitmatrix64_find_masked_row(uint64_t *m, uint32_t i, uint64_t mask, uint64_t v)
Find (masked) row of a bit matrix with a certain value.
Here bit matrix
m
hasi
rows.The function returns the lowest index
k
such thatm[k] & mask == v
holds. The function returns ERR_QSTATE12_NOTFOUND if no suchk
exists.
- int32_t bitmatrix64_to_numpy(uint64_t *m, uint32_t rows, uint32_t cols, uint8_t *a)
Convert bit matrix to numpy array.
Here bit matrix
m
hasrows
rows andcols
columns.Then
a
bust be an array ofrows * cols
bytes length. The function writes the bitm[i,j]
toa[i * cols + j]
.The function returns rows * cols in case of success and ERR_QSTATE12_NOTFOUND in case of failure, e.g. if
cols > 64
.
- void bitmatrix64_from_32bit(uint32_t *a32, uint32_t n, uint64_t *a64)
Copy array of 32-bit integers to array of 64-bit integers.
Copy the array
a32
ofn
32-bit integers to the arraya64
ofn
64-bit integers. Entries of the array are zero extended.
- void bitmatrix64_to_32bit(uint32_t *a32, uint32_t n, uint64_t *a64)
Copy array of 64-bit integers to array of 32-bit integers.
Copy the array
a64
ofn
64-bit integers to the arraya32
ofn
32-bit integers. Upper 32 bits of the entries are dropped.
- uint32_t bitmatrix64_find_low_bit(uint64_t *m, uint32_t imin, uint32_t imax)
Find position of lowest bit in a bit matrix.
The function returns the lowest position
k
of a bit in the bit matrixm
, which is set to one. It scans only the bits at positionsimin <= k < imax
. If all bits at these positions are zero then the function returnsimax
.Here bit
j
ofm[i]
is considered at position64*i + j
. Bit matrixm
should have at least(imax + 63) >> 6
entries.
- void bitmatrix64_mul(uint64_t *m1, uint64_t *m2, uint32_t i1, uint32_t i2, uint64_t *m3)
Bit matrix multiplication.
Here
m1
andm2
havei1
andi2
rows, respectively. Only the lowesti2
columns ofm1
are inspected. Matrixm2
may have any number of columns, up to 64.The function computes the matrix product
m1 * m2
in the arraym3
. Matrixm3
hasi1
rows and the same number of columns asm2
.Array
m3
may be equal to arraym1
; but it may not overlap withm2
.
- uint64_t bitmatrix64_vmul(uint64_t v, uint64_t *m, uint32_t i)
Multiplication of a vector with a bit matrix.
Here matrix
m
hasi
rows; andv
is a bit vector. The function returns the product of the bit vectorv
with the bit matrixm
. If bit vectorv
hask
leading zero bits then only the lowest64 - k
rows of matrixm
are inspected.
- int32_t bitmatrix64_rot_bits(uint64_t *m, uint32_t i, int32_t rot, uint32_t nrot, uint32_t n0)
Rotate columns of a bit matrix.
Here bit matrix
m
hasi
rows.For
n0 <= j < n0 + nrot
we map columnj
of matrixm
to columnn0 + (j + rot) % nrot
. E.g.nrot = 3, rot = 1, n0 = 0
means that columns are mapped as0->1, 1->2, 2->0
.The function returns 0 in case of success and a negative value if any column with index >= 64 is involved in the rotation.
- int32_t bitmatrix64_xch_bits(uint64_t *m, uint32_t i, uint32_t sh, uint64_t mask)
Exchange columns of a bit matrix.
Here bit matrix
m
hasi
rows.Exchange column
j
with columnj + sh
of the bit matrixm
, if bitj
ofmask
is set. If bitj
ofmask
is set then bitj + sh
ofmask
must not be set. No bit ofmask
at position greater or equal to64 - sh
may be set.E.g.
qstate12_xch_bits(
m, 1, 0x11)
maps columns (…,6,5,4,3,2,1,0) to columns (…,6,4,5,3,2,0,1).The function returns 0 in case of success and a negative value if any column with index >= 64 is involved in the operation.
- int32_t bitmatrix64_reverse_bits(uint64_t *m, uint32_t i, uint32_t n, uint32_t n0)
Reverse columns of a bit matrix.
Here bit matrix
m
hasi
rows.The function reverses
n
columns of the bit matrixm
starting at columnn0
. So it exchanges bitm[k, n0 + j]
with bitm[k, n0 + n - 1 - j]
for0 <= j < n
and0 <= k < i
`.The function returns 0 in case of success and a negative value if any column with index >= 64 is involved in the operation.
- int32_t bitmatrix64_t(uint64_t *m1, uint32_t i, uint32_t j, uint64_t *m2)
Transpose a bit matrix.
Here
m1
is ani
timesj
bit matrix. Here bitm1[m,n]
is given by(m1[m] >> n) & 1
. The function writes the transposed bit matrix ofm1
tom2
.
- uint32_t bitmatrix64_echelon_h(uint64_t *m, uint32_t i, uint32_t j0, uint32_t n)
Convert bit matrix
m
to reduced row echelon form.Matrix
m
hasi
rows. Here we assume that the leading bit of a row of matrixm
is the most significant bit in that row. For echelonizingm
, we pivot over nolumnsj0-1,...,j0-n
in that order, ignoring the other columns. We perform row operations (on all possible columns 0,…,63) for changing matrixm
.The function returns the number of rows in the (echelonized) matrix
m
that have a nonzero bit in at least one of the pivoted columns.
- uint32_t bitmatrix64_echelon_l(uint64_t *m, uint32_t i, uint32_t j0, uint32_t n)
Convert bit matrix
m
to reduced row echelon form.Matrix
m
hasi
rows. Here we assume that the leading bit of a row of matrixm
is the least significant bit in that row. For echelonizingm
, we pivot over columnsj0,...,j0+n-1
in that order, ignoring the other columns. We perform row operations (on all possible columns 0,…,63) for changing matrixm
.The function returns the number of rows in the (echelonized) matrix
m
that have a nonzero bit in at least one of the pivoted columns.
- int32_t bitmatrix64_cap_h(uint64_t *m1, uint64_t *m2, uint32_t i1, uint32_t i2, uint32_t j0, uint32_t n)
Compute intersection of row spaces of two bit matrices.
Bit matrix
m1
hasi1
rows, and bit matrixm2
hasi2
rows. Both matrices,m1
andm2
, must be given in reduced echelon form in the sense of functionbitmatrix64_echelon_h
.The function changes
m1
andm2
using row operations in such a way that the lower rows ofm1
andm2
contain the intersection of the rows spaces of the two matrices. For computing that intersection we consider only columnsj0-1,...,j0-n
of matricesm1
andm2
. However, we do each row operation on all possible columns63,...,0
.The function returns the dimension
n_cap
of the intersection of the row spaces ofm1
andm2
, ignoring all columns except for columnsj0-1,...,j0-n
.Assume that the echelonized input matrices
m1
(andm2
) haver1
(andr2
) leading rows that have at least one nonzero bit in columnsj0-1,...,j0-n
, respectively. Then the function changes the leadingr1
rows ofm1
and the leadingr2
rows ofm2
only. These rows are changed in such a way that the lastn_cap
of these rows of the two matrices are equal in columnsj0-1,...,j0-n
. So these last rows contain the intersection of the row spaces ofm1
andm2
`, ignoring all columns butj0-1,...,j0-n
.Parameters
j0
andn
must be the same in this function, and in the previous two calls to functionbitmatrix64_echelon_h
used for echelonizing matricesm1
andm2
. This function computes garbage in the arraysm1
andm2
, unless both matrices,m1
andm2
, have been echelonized in that way before calling this function.A negative return value
n_cap
means that at least one of the input matricesm1
andm2
has not been echelonized correctly. This function may or may not detect an incorrect echelonization of an input matrix.
- int32_t bitmatrix64_inv(uint64_t *m, uint32_t i)
Bit matrix inversion.
Here
m
hasi
rows andi
columns.i <= 32
must hold. The function inverts matrixm
in place.It returns 0 in case of success and
ERR_QSTATE12_MATRIX_INV
ifm
is not invertible.
- int64_t bitmatrix64_solve_equation(uint64_t *m, uint32_t i, uint32_t j)
Solve a linear bit equation.
Let
M
be the bit matrix withi
rows andj
columns stored in the arraym
in the usual way. Letv
be the column bit vector stored in columnj
of the arraym
.Then the function tries to solve the equation
transpose(v) * m = x
If such a solutionx
exists then the function returns the transposed vector of the column vectorx
as a nonnegative integer.The function returns
ERR_QSTATE12_MATRIX_INV
if no solutionx
exists. As a side effect, it echelonizes the lowestj + 1
columns of matrixm
with functionbitmatrix64_echelon_h
.
C functions in uint_sort.c
File
uint_sort.c
contains functions for sorting arrays of unsigned 32-bit and 64-bit integers.Functions
- void bitvector32_copy(uint32_t *a_src, uint32_t n, uint32_t *a_dest)
Copy an array to type
uint32_t[]
Copy the array
a_src
of lengthn
toa_dest
. Any kind of overlap is supported.
- void bitvector32_heapsort(uint32_t *a, uint32_t n)
Sort an array
a
of lengthn
with heap sort.Here
a
is an array ofn
integers of typeuint32_t
. The array is sorted in place. The function is exported for debuging. You should use functionbitvector32_sort
.
- void bitvector32_sort(uint32_t *a, uint32_t n)
Sort an array
a
of typeuint32_t[]
of lengthn
Here
a
is an array ofn
integers of typeuint32_t
. The array is sorted in place.We use quicksort as the main sorting algorithm. If quicksort reaches a certain recursion level then we switch to heap sort. This guarantees a run time of \(O(n \mathop{log}(n))\). For small arrays we use insert sort.
- void bitvector64_copy(uint64_t *a_src, uint32_t n, uint64_t *a_dest)
Copy an array to type
uint64_t[]
Copy the array
a_src
of lengthn
toa_dest
. Any kind of overlap is supported.
- void bitvector64_heapsort(uint64_t *a, uint32_t n)
Sort an array
a
of lengthn
with heap sort.Here
a
is an array ofn
integers of typeuint64_t
. The array is sorted in place. The function is exported for debuging. You should use functionbitvector64_sort
.
- void bitvector64_sort(uint64_t *a, uint32_t n)
Sort an array
a
of typeuint64_t[]
of lengthn
Here
a
is an array ofn
integers of typeuint64_t
. The array is sorted in place.We use quicksort as the main sorting algorithm. If quicksort reaches a certain recursion level then we switch to heap sort. This guarantees a run time of \(O(n \mathop{log}(n))\). For small arrays we use insert sort.
C functions in qstate12.c
File
qstate12.c
contains functions for quadratic state matrices as described in the API reference in section Computation in the Clifford group.C functions in this module are prefixed with
qbstate12_
. Unless otherwise stated, these functions return anint32_t
, where a nonegative value is interpreted as success, and a negative value is intepreted as failure. Error codes are documented in fileclifford12.h
.Typical names for parameters of functions in this module are:
Name | Parameter type -------------- | ---------------------------------------------- pqs, pqs1, ... | Pointer to structure of type qbstate12_type nqb | Number of qubits, i.e. of columns of matrix | A in a structure of type qbstate12_type. nrows | Number of rows of matrix A or Q | in a structure of type qbstate12_type. i, i1, ... | Index of a row of matrix A or Q , | starting with 0. j, j1, ... | Index of a column of matrix A , with a | column of A , corrsesponding to a qubit, | starting with j = 0. | If appropriate, an index j >= ncols refers | to column (j - ncols) of matrix Q . pv, pv1,... | Pointer to a row or column vector of matrix | A, Q or M .Functions
- int32_t qstate12_check(qstate12_type *pqs)
Check a structure of type
qstate12_type
.Return 0 if ok, or an error code if there is any error in the structure referred by
pqs
. PartQ[i,0]
is set toQ[0, i]
. PartQ[0,0]
is set ot 0. Irrelevant data bits in valid data rows are zeroed.
- int32_t qstate12_set_mem(qstate12_type *pqs, uint64_t *data, uint32_t size)
Assign memory to a structure of type
qstate12_type
.Assign the array
data
ofsize
integers of typeuint64_t
as memory to structure of typeqstate12_type
referred bypqs
.
- int32_t qstate12_zero(qstate12_type *pqs, uint32_t nqb)
Set a structure of type
qstate12_type
to a zero vector.Set the structure referrred by
pqs
to a zero column vector of length2**nqb
, corresponding to the zero state ofnqb
qubits.
- int32_t qstate12_vector_state(qstate12_type *pqs, uint32_t nqb, uint64_t v)
Set a structure of type
qstate12_type
to a state vector.Set the structure referrred by
pqs
to a unit column vector|v>
of length2**nqb
. Thus for the quadratic mappingqs
referred bypqs
we haveqs(x) = 1
ifx
is equal to the bit vectorv
andqs(x) = 0
otherwise.
- int32_t qstate12_set(qstate12_type *pqs, uint32_t nqb, uint32_t nrows, uint64_t *data, uint32_t mode)
Set a data in a structure of type
qstate12_type
Set
pqs->nqb = nqb
so that the stateqs
referred bypqs
corresponds to a column vector of length2**nqb
. Setpqs->nrows = nrows
, and copynrows
rows of the arraydata
topqs->data
.If
mode == 1
then copy the upper triangular part of the data bit matrix partQ
to the lower triangular part.If
mode == 2
then copy the lower triangular part of the data bit matrix partQ
to the upper triangular part.Otherwise the part
Q
of the data bit matrix must be symmetric.The resulting state is checked with function qstate12_check().
- int32_t qstate12_copy(qstate12_type *pqs1, qstate12_type *pqs2)
Copy a state of type
qstate12_type
to another state.Copy the data in the state referred by
pqs1
to the data in the state referred bypqs2
. Memory must have been allocated to the statepqs2
with function qstate12_set_mem()
- int32_t qstate12_copy_alloc(qstate12_type *pqs1, qstate12_type *pqs2, uint64_t *data, uint32_t size)
Copy a state of type
qstate12_type
and allocate mamory.Equivalent to
qstate12_set_mem(pqs2, data, size); qstate12_copy(pqs1,pqs2);
- int32_t qstate12_factor_to_complex(int32_t factor, double *pcomplex)
Convert a scalar factor to a complex number.
The function takes a scalar
factor
(as given by the componentfactor
in the structureqstate12
) and converts that factor to a complex number. The real part of the result is returned inpcomplex[0]
and the imaginary part inpcomplex[1]
.Caution:
If bit 3 of
factor
is set then the function calculates the complex number 0.The function returns:
4 if the result is complex, but not real. 3 if the result is real, but not rational. 2 if the result is rational, but not integral. 1 if the result is integral, but not zero. 0 if the result is zero. ERR_QSTATE12_SCALAR_OVFL in case of overflow or underflow
- int32_t qstate12_factor_to_int32(int32_t factor, int32_t *pi)
Convert a scalar factor to a 32-bit integer.
The function takes a scalar
factor
(as given by the componentfactor
in the structureqstate12
) and converts that factor to an integer. That integer is stored inpi[0]
.Caution:
If bit 3 of
factor
is set then the function calculates the integer zero.The function returns:
1 if the result is integral, but not zero.
0 if the result is zero.
ERR_QSTATE12_SCALAR_OVFL in case of overflow or underflow
ERR_QSTATE12_SCALAR_INT if the result is not an integer
- int32_t qstate12_conjugate(qstate12_type *pqs)
Conjugate the state referred by
pqs
The function changes the state referred by
pqs
to its complex complex state.
- int32_t qstate12_mul_scalar(qstate12_type *pqs, int32_t e, uint32_t phi)
Multiply the state referred by
pqs
by a scalar.The function multiplies the state
qs
referred bypqs
with the scalar2**(e/2) * exp(phi * pi * sqrt(-1) / 4) .
- int32_t qstate12_abs(qstate12_type *pqs)
Replace entries of a state by their absolute values.
The function replaces the entries of the state referred by
pqs
by their absolute values.
- uint64_t qstate12_get_column(qstate12_type *pqs, uint32_t j)
Return column
j
of the bit matrixM
stored inpqs->data
as a bit vector in an integer of typeuin64_t
.
- int32_t qstate12_del_rows(qstate12_type *pqs, uint64_t v)
Delete all rows
i, 1 <= i < pqs->nrows,
from the bit matrixM
stored inpqs->data
, if biti
in the bit vector*pv
is set. Here we also adjust the quadratic formQ
which is part of the bit matrixM
. Row 0 is never deleted.
- int32_t qstate12_insert_rows(qstate12_type *pqs, uint32_t i, uint32_t nrows)
Insert
nrows
zero rows into the bit matrixM
stored inpqs->data
, starting before rowi
. The corresponding zero columns of the quadratic formQ
, which is part of the bit matrixM
, are also inserted.1 <= i <= nrows
must hold. This process multiplies the state vector by the scalar2**nrows
.
- int32_t qstate12_mul_Av(qstate12_type *pqs, uint64_t v, uint64_t *pw)
Let
M
be the bit matrix stored inpqs->data
. We return the matrix productw = A * Transposed(v)
, whereA
is theA
part of the bit matrixM
, as a bit vector.
- int32_t qstate12_rot_bits(qstate12_type *pqs, int32_t rot, uint32_t nrot, uint32_t n0)
Rotate qubit arguments of the state
qs
referred bypqs
.For
n0 <= i < n0 + nrot
we map qubiti
to qubitn0 + (i + rot) % nrot
. E.g.nrot = 3, rot = 1, n0 = 0
means that bits are mapped as0->1, 1->2, 2->0
. Letnn1 = pqs->ncols
. Then the function changes the quadratic mappingqs
to referred bypqs
toqs1
withqs1(x[nn1-1],...,x[n0+nrot],y[nrot-1],...,y[0],x[n0-1],...,x[0]) = qs(x[nn1-1],...,x[n0+nrot],z[nrot-1],...,z[0],x[n0-1],...,x[0]),where
z[j] = y[j - rot (mod 3)]
.
- int32_t qstate12_xch_bits(qstate12_type *pqs, uint32_t sh, uint64_t mask)
Exchange qubit arguments of the state
qs
referred bypqs
.Exchange qubit
j
with argument bitj + sh
of the stateqs
referred bypqs
, if bitj
ofmask
is set. If bitj
ofmask
is set then bitj + sh
ofmask
must not be set. No bit ofmask
at position greater or equal topqs->ncols - sh
may be set.E.g.
qstate12_xch_bits(pqs, 1, 0x11)
changes the quadratic mappingqs
toqs1
withqs1(...,x6,x5,x4,x3,x2,x1,x0) = qs(...,x6,x4,x5,x3,x2,x0,x1) .
- void qstate12_pivot(qstate12_type *pqs, uint32_t i, uint64_t v)
Auxiliary function for function qstate12_reduce().
Let
M
be the bit matrix stored inpqs->data
. The pivoting process is controlled by the bit vectorv
. Ifk < i
and bitk
ofv
is set then rowi
of bit matrixM
is xored to rowk
ofM
. The columns of the partQ
ofM
are also adjusted.1 <= i < pqs->nrows
must hold. Pivoting does not change the state.For internal use only. Input conditions are not checked.
- int32_t qstate12_sum_up_kernel(qstate12_type *pqs)
Auxiliary function for function qstate12_reduce().
Sum up the kernel of the transformation matrix
A
, which is part of the bit matrixM = pqs->data
. We assume thatA
is echelonized in the sense that all nonzero rows ofA
are linear independent and that they occur before the zero rows.
- int32_t qstate12_echelonize(qstate12_type *pqs)
Convert the state represented by
pqs
to echelon form.The representation state referred by
pqs
is converted to (not necessarily reduced) echelon form, and the kernel of bit matrixA
, which is part of the bit matrixM = pqs->data
is summed up as described in the guide, section ‘Reducing the representation of a quadratic mapping’. The representation of the state is not changed if this is already the case.This function does not change the state.
- int32_t qstate12_check_reduced(qstate12_type *pqs)
Check if the state represented by
pqs
is reduced.The function puts
pqs->reduced = 1
if the state is reduced; and it performs no action onpqs
otherwise. It returns the updated value ofpqs->reduced
(which is 0 or 1) in case of success, and a negative value in case of failure.This check is much faster than actually performing a reduction. The function may perform some easy reduction steps on the state.
- int32_t qstate12_reduce(qstate12_type *pqs)
Reduce the state represented by
pqs
The representation state referred by
pqs
is converted to reduced echelon form, and the kernel of bit matrixA
, which is part of the bit matrixM = pqs->data
is summed up as described in the guide, section ‘Reducing the representation of a quadratic mapping’. The representation of the state is not changed if this is already the case.This function does not change the state.
- int32_t qstate12_row_table(qstate12_type *pqs, uint8_t *row_table)
Compute a certain table for the state referred by
pqs
Compute a row table for the state
qs
referred bypqs
. Hereqs
must be in (not necessarily reduced) echelon form.The function computes
row_table[j] = i
if the leading bit of rowi
of partA
of the bit matrixM = pqs->data
is in columnj
, for0 <= j < pqs->ncols
and1 <= i < pqs->nrows
. If now such row exists for columnj
then we putrow_table[j] = QSTATE12_UNDEF_ROW
.The representation of the state is not changed.
- int32_t qstate12_equal(qstate12_type *pqs1, qstate12_type *pqs2)
Check equality of two states.
Return 1 if the states referred by
pqs1
andpqs2
are equal, 0 if not, and a negative number in case of error. Both states are reduced before comparing them.
- int32_t qstate12_extend_zero(qstate12_type *pqs, uint32_t j, uint32_t nqb)
Insert qubits into a state and set them to 0.
We insert
nqb
zero qubits into the stateqs
referred bypqs
starting at positionj
.Let
n = pqs->ncols
so that the stateqs
referred bypqs
depends onn
qubits. We changeqs
to the following stateqs1
depending onn + nqb
qubits:
qs1(x[n-1],...,x[j],y[nqb-1],...,y[0],x[j-1]...,x[0])
is equal toqs(x[n-1],...,x[j],x[j-1]...,x[0])
ify[0] = ... = y[nqb-1] = 0
and equal to zero otherwise. So we incrementpqs->ncols
bynqb
.If the input is reduced then the result is also reduced.
pqs->shape1
is set to 0, i.e. a column vector is returned.
- int32_t qstate12_extend(qstate12_type *pqs, uint32_t j, uint32_t nqb)
Insert qubits into a state.
We insert
nqb
qubits into the stateqs
referred bypqs
starting at positionj
.Let
n = pqs->ncols
so that the stateqs
referred bypqs
depends onn
qubits. We changeqs
to the following stateqs1
depending onn + nqb
qubits:
qs1(x[n-1],...,x[j],y[nqb-1],...,y[0],x[j-1]...,x[0])
is equal toqs(x[n-1],...,x[j],x[j-1]...,x[0])
. So we incrementpqs->ncols
bynqb
.The result is not reduced.
pqs->shape1
is set to 0, i.e. a column vector is returned.
- int32_t qstate12_sum_cols(qstate12_type *pqs, uint32_t j, uint32_t nqb)
Sum up the functional values for some qubits.
We sum up
nqb
qubits of the stateqs
referred bypqs
starting at positionj
.Let
n = pqs->ncols
so that the stateqs
referred bypqs
depends onn
qubits. We changeqs
to the following stateqs1
depending onn - ncols
qubits:
qs1(x[n-1],...,x[j+nqb],x[j-1],...,x[0])
=sum_{x[j+nqb-1],...,x[j]} qs1(x[nn1-1],...,x[0])
. So we decrementpqs->ncols
bynqb
.The output is not reduced.
pqs->shape1
is set to 0, i.e. a column vector is returned.
- int32_t qstate12_restrict_zero(qstate12_type *pqs, uint32_t j, uint32_t nqb)
Restrict
nqb
qubits starting at postionj
to 0.Let
n = pqs->ncols
so that the stateqs
referred bypqs
depends onn
qubits. We changeqs
to the following stateqs1
depending onn
qubits:
qs1(x[n-1],...,x[0])
is equal toqs(x[n-1],...,x[0])
ifx[j] = ... = x[j+nqb-1] = 0
and equal to zero otherwise. We do not change the shape ofqs
.The output is reduced if the input is reduced.
- int32_t qstate12_restrict(qstate12_type *pqs, uint32_t j, uint32_t nqb)
Restrict some qubits to 0 and delete them.
Similar to function
qstate12_restrict_zero
, but with deleting the restricted qubits.Let
n = pqs->ncols
so that the stateqs
referred bypqs
depends onn
qubits. We changeqs
to the following stateqs1
depending onn1 = n - nqb
qubits:
qs1(x[n1-1],...,x[0])
is equal toqs(x[n1-1],...,x[j],0,...,0,x[j-1],...,x[0])
. So we decrementpqs->ncols
bynqb
.The output is not reduced.
pqs->shape1
is set to0
, i.e. a column vector is returned.In quantum computing theory this operation can be interpreted as measurement of the corresponding qubits with postselection, setting all measured qubits to 0.
- int32_t qstate12_gate_not(qstate12_type *pqs, uint64_t v)
Apply a not gate to a state.
Change the state
qs
referred bypqs
to a stateqs1
withqs1(x) = qs(x (+) v)
, where'(+)'
is the bitwise xor operation. The result is not reduced.Computing
qstate12_gate_not(pqs, 1 << j)
corresponds to negating qubitj
.
- int32_t qstate12_gate_ctrl_not(qstate12_type *pqs, uint64_t vc, uint64_t v)
Apply a contol-not gate to a state.
Change the state
qs
referred bypqs
to a stateqs1
withqs1(x) = qs(x (+) <vc,x> * v)
, where'(+)'
is the bitwise xor operation, and<.,.>
is the scalar product of bit vectors. The result is not reduced. The scalar product of the bit vectorsj
andjc
must be zero. Otherwise thectrl not
operation is not unitary.Computing
qstate12_gate_ctrl_not(pqs, 1 << jc, 1 << j)
, forjc != j
, corresponds to applying a controlled not gate to qubitj
, contolled by qubitjc
.
- int32_t qstate12_gate_phi(qstate12_type *pqs, uint64_t v, uint32_t phi)
Apply a phase gate to a state.
Change the state
qs
referred bypqs
to a stateqs1
withqs1(x) = qs(x) * sqrt(-1)**(phi * <v,x>)
, where<.,.>
is the scalar product of bit vectors and'**'
denotes exponentiation. The result is reduced if the input is reduced. Computingqstate12_gate_ph(pqs, 1 << j, phi)
corresponds to applying a phase(phi * pi/2)
gate to qubitj
.
- int32_t qstate12_gate_ctrl_phi(qstate12_type *pqs, uint64_t v1, uint64_t v2)
Apply a controlled phase gate to a state.
Change the state
qs
referred bypqs
to a stateqs1
withqs1(x) = qs(x) * (-1)**(<v1,x>*<v2,x>)
, where<.,.>
is the scalar product of bit vectors and'**'
denotes exponentiation.The result is reduced if the input is reduced. Computing
qstate12_gate_ctrl_phi(pqs, 1 << j1, 1 << j2)
corresponds to applying a phasepi
gate to qubitj2
controlled by qubitj1
.
- int32_t qstate12_gate_h(qstate12_type *pqs, uint64_t v)
Apply Hadamard gates to a state.
Apply a Hadamard gate to all qubits
j
of the stateqs
(referred by pqs) withv & (1 << j) == 1
. Applying a Hadamard gate to gatej
changes a stateqs
to a state1/sqrt(2) * qs1
, whereqs1(..,x[j+1],x_j,x[j-1],..)
=qs(..,x[j+1],0,x[j-1],..)
(-1)**(x_j) * qs(..,x[j+1],1,x[j-1],..)
. The result is not reduced.
C functions in qstate12io.c
File
qstate12io.c
contains functions for converting quadratic state matrices as described in the API reference in section Computation in the Clifford group to complex numbers.The function in this module are coded according the conventions in module
qstate12.c
.Functions
- int32_t qstate12_complex(qstate12_type *pqs, double *pc)
Expand a state to an array of complex numbers.
Expand the state
qs
referred bypqs
to the array referred by the pointerpc
. The real part ofqs[i]
is stored inpc[2*i]
and the imaginary part ofqs[i]
is stored inpc[2*i+1]
. The function reducesqs
. Here the integeri
is interpreted as a bit vector as usual.
pqs->shape1
is ignored. The user has to care for the shape of the returned array. The stateqs
is reduced.Caution: The function sets
2 * 2**pqs->ncols
entries in the arraypc
.Return value is as in function
qstate12_entries
.
- int32_t qstate12_entries(qstate12_type *pqs, uint32_t n, uint32_t *v, double *pc)
Convert entries of a state to complex numbers.
The function computes the entries
qs[v[i]]
of the stateqs
referred bypqs
for0 <= i < n
and stores these entries in the arraypc
. The real part ofqs[v[i]]
is stored inpc[2*i]
and the imaginary part is stored inpc[2*i+1]
. The stateqs
is reduced.Caution: The function sets
2 * n
entries in the arraypc
.Depending on the computed matrix entries, the function returns
4 if all entries are complex, but not all are real. 3 if all entries are real, but not all are rational. 2 if all entries are rational, but not all are integers. 1 if all entries are integers, but not all are zero. 0 if all entries are zero.A negative return value indicates an error.
- int32_t qstate12_int32(qstate12_type *pqs, int32_t *pi)
Expand a state to an array of 32-bit integers.
Expand the state
qs
referred bypqs
to the array of integers (of typeint32_t
) referred by the pointerpi
. Hereqs[i]
is stored inpi[i]
. The function reducesqs
. The integeri
is interpreted as a bit vector as usual.
pqs->shape1
is ignored. The user has to care for the shape of the returned array. The stateqs
is reduced.Caution: The function sets
2**pqs->ncols
entries in the arraypc
.The function returns 0 in case of success, and a negative value in case of error, e.g. if
qs
is not integral or in case of integer overflow.
- int32_t qstate12_to_signs(qstate12_type *pqs, uint64_t *bmap)
Store the signs of a real quadratic state in an array.
Let
qs
be the quadratic state matrix referred bypqs
. Assume thatqs
is real and has shape(I, J)
. Lett[i * 2**J + j] = 0, 1, or 3
, if entryqs[i, j]
is zero, positive, or negative, respectively. Then we storet[k]
in bits2 * l + 1, 2 * l
ofbmap[k >> 5]
, withl = k & 0x1f
.The function returns 0 in case of success, and a negative value in case of error, e.g. if
qs
is not a real matrix.
- int32_t qstate12_compare_signs(qstate12_type *pqs, uint64_t *bmap)
Compare signs of a real quadratic state with an array.
Let
qs
andbmap
as in functionqstate12_to_signs
. The function returns 1 if the signs ofqs
are stored in inbmap
as described in functionqstate12_to_signs
. Otherwise the function returns 0. The function also returns 0 if matrixqs
is not real. It returns a negative value in case of an error.
- int32_t qstate12_from_signs(uint64_t *bmap, int32_t n, qstate12_type *pqs)
Construct a state vector from a sign matrix.
Let
bmap
be an array with2**n
entries representing 0 or (positive or negative) signs as in functionqstate12_to_signs
. Thenbmap
may correspond to a quadratic state vector with entries 0, 1, and -1.If these enrties correspond to a quadratic state vector
V
(with entries 0, 1, and -1) then the function storesV
in the quadratic state vectorqs
referred bypqs
and returns 0. The returned stateqs
is a (column) vector of shape(0, n)
. If the arraybmap
does not correspond to any quadtatic state vector then the function setsqs
to the zero vector of shape(0, n)
and returns -1.The function returns negative value less than -1 in case of an error.
- int32_t qstate12_mul_matrix_mod3(qstate12_type *pqs, uint64_t *v, uint64_t w)
Compute a certain product modulo 3 with a state matrix.
Let
qs
be the quadratic state matrix referred bypqs
. Assume thatqs
is rational and has shape(I, J)
. Letq
be the row vector of length2**(I+J)
withq[i * 2**J + j] = qs[i, j]
.We consider
v
as a2**(I+J)
times32
matrixM
of integers modulo 3 withM[k,l]
stored in bits2*l+1
and2*l
of entryv[k]
. We considerw
as a column vector of32
integers mod 3 withw[l]
stored in bits2*l+1
and2*l
of the variablew
.Then the function returns the matrix product
q * M * v
(modulo 3) as a nonnegative integer less than 3. It returns a negative value in case of error, e.g. ifqs
is not rational.
C functions in qmatrix12.c
File
qmatrix12.c
contains basic functions for quadratic
state matrices as described in the
API reference in section Computation in the Clifford group. The functions is this module are based on the functions in moduleqstate.c
and on the data structures defined in moduleclifford12.h
.C functions in this module are prefixed with
qbstate12_
. Unless otherwise stated, these functions return anint32_t
, where a nonegative value is interpreted as success, and a negative value is intepreted as failure. Error codes returned by functions in this module are documented in fileclifford12.h
.A structure
qs
of typeqstate12_type
defines a function \(f: \mathbb{F}_2^n \rightarrow \mathbb{C}\) and also a \(2^{n-k} \times 2^k\) matrix \(M\) with entries \(M[i,j] = f(2^k \cdot i+j)\). Here we idenitfy the nonegative integers \( < 2^n\) with the bit vectors given by their binary representation. For the shape parameters \(n, k\) of a stateqs
we have \(n\) =qs.ncols
, \(k\) =qs.qstate1
. Thus indices of vectors and matrices start with 0, as usual in C and python.While the functions in module
qstate.c
mostly ingnore the shape parameter \(k\), the functions in this module use that shape parameter for determining the shape of a matrix.Functions
- int32_t qstate12_std_matrix(qstate12_type *pqs, uint32_t rows, uint32_t cols, uint32_t rk)
Create a standard matrix with entries 1 in the diagonal.
Create a standard matrix
qs
with2**rows
rows and2**cols
columns as an object of typeqstate12_type
, and store the result in*pqs
. Diagonal entriesqs[i,i]
are equal to one forì < 2**rk
. All other entries of the matrix are zero.0 <= rk < min(nows, cols)
must hold.
- int32_t qstate12_unit_matrix(qstate12_type *pqs, uint32_t nqb)
Create a unit matrix.
Create a unit matrix with
2**nqb
rows and2**nqb
columns as an object of typeqstate12_type
, and store the result in*pqs
.
- int32_t qstate12_monomial_column_matrix(qstate12_type *pqs, uint32_t nqb, uint64_t *pa)
Create matrix with one nonzero entry in each column.
Create a matrix
T
with2**nqb
rows and2**nqb
columns as an object of typeqstate12_type
, and store the result in*pqs
.Matrix
T
is a real2**nqb
times2**nqb
transformation matrix which is monomial in the sense that each column contains exactly one nonzero entry 1 or -1. So left multiplication withT
maps unit vectors to (possibly negated) unit vectors. It transforms a complex column vectorw
of length2**nqb
to a vectorT * w
.
pa
refers to an array a of integersa[i]
of lengthnqb + 1
. Each integera[i]
is interpreted as a bit field via its binary representation. Soa[i,j]
means(a[i] >> j) & 1
.a[i, j1:j2]
means the bit fielda[i,j1],...,a[i,j2-1]
.For any bit vector
v
of lengthnqb
let|v>
be the unit vector with indexv
. For any bit vectorv
of lengthnqb + 1
let|v>
be the (possibly negated) unit vector(-1)**v[nqb] * |v[0:nqb]>
.|v1 ^ v2>
and|1 << v1>
are defined via the corrresponding operators<<
and^
in C.Then
T
maps|0> to |a[0, 0:nqb+1]> |1 << i> to |a[0, 0:nqb+1] ^ a[i+1, 0:nqb+1]>
T
maps unit vectors to (possibly negated) unit vectors, soT(v)
is well defined by|T(v)> = T(|v>)
for a bit fieldv
of lengthnqb + 1
. We have|T(v1 ^ v2)> = (-1)**Q(v1,v2) * |T(v1) ^ T(v2) ^ T(0)>,for bit fields
v1, v2
of lengthnqb + 1
and an alternating bilinear formQ
depending on the lowestnqb
bits ofv1
andv2
only. ThusT
is defined by the above equation andQ
. The bilinear formQ
is defined by:Q(v1, v2) = Q(v2, v1), Q(v1, v1) = 0, and Q(1 << i, 1 << j) = a[i + 1, j + nqb + 1]``, for ``0 <= j < i < nqb``.
- int32_t qstate12_monomial_row_matrix(qstate12_type *pqs, uint32_t nqb, uint64_t *pa)
Create matrix with one nonzero entry in each row.
Similar to qstate12_monomial_column_matrix(); but we create a matrix
T
which is monomial in the sense that each row contains exactly one nonzero entry1
or-1
.qstate12_monomial_row_matrix(*pqs, nqb, *pa)
creates the transposed matrix ofqstate12_monomial_column_matrix(*pqs, nqb, *pa)
.
- int32_t qstate12_monomial_matrix_row_op(qstate12_type *pqs, uint32_t *pa)
Obtain operation of a monomial quadratic state matrix.
A monomial matrix maps unit vectors to unit vectors, if we ignore scalar factors. Let
qs
be the matrix referred bypqs
. We assume thatqs
has exactly one nonzero entry in each row. Then right multiplication withqs
maps unit vectors to unit vectors, up to a scalar factor. Otherwrise the function returns ERR_QSTATE12_NOT_MONOMIAL.If we label each unit vector by a bit vector then the operation of
qs
on these bit vectors labels is affine. Ifqs
has shape(r,c)
then we compute anr+1
timesc
bit matrixa
in the array referred bypa
with the following property:Label
(b[0],...,b[r-1])
is mapped to label(1, b[0],...,b[r-1]) * a
.The function returns the number
r+1
of rows ofa
.From bit matrix
a
we can construct a unique matrixqs1
, of the same shape asqs
, that maps unit vectors to unit vectors as given by the mapping of the labels. In caser == c
this can be done by callingqstate12_monomial_row_matrix(pqs1, r, pa)
, wherepqs1
points to a buffer forqs1
.Then
qs
can be obtained by multiplyingqs1
with a diagonal matrix.
- int32_t qstate12_mat_reshape(qstate12_type *pqs, int32_t rows, int32_t cols)
Change the shape of a matrix.
Reshape the matrix
T
referred bypqs
will be a2**rows
times2**cols
matrix.The old shape of the matrix is
(n-k, k)
withn, k
given byn = pqs->ncols
,k = pqs->shape1
. Reshaping must not change the number of entries, sorows + cols == n
must hold. We follow the convention in the python numpy package for reshaping matrices. Thus index[i,j]
of a matrix with shape(I,J)
corresponds to the indexi * 2**J + j
in the one-dimensional array storing that matrix.If
rows
orcols
is -1 then it is calculated from the old shape of the matrix. If both,rows
andcols
, are -1 thenrows
is set to0
andcols
is calculated.
- int32_t qstate12_mat_t(qstate12_type *pqs)
Transpose a matrix in place.
The quadratic state matrix
qs
referred bypqs
is transposed in place. The result is not reduced.
- int32_t qstate12_mat_trace(qstate12_type *pqs, double *p_trace)
Compute the trace of a quadratic state matrix.
The function computes the trace of the quadratic state matrix
qs
referred bypqs
. The real part of the trace is stored inp_trace[0]
and the imaginary part is stored inp_trace[1]
. The stateqs
is reduced.Return value is as in function
qstate12_factor_to_complex
.
- int32_t qstate12_mat_itrace(qstate12_type *pqs, int32_t *p_itrace)
Compute the trace of a quadratic state matrix.
Similar to function
qstate12_mat_trace
, buth the trace is stored as an integer inp_itrace[0]
.Return value is as in function
qstate12_factor_to_int32
.
- int32_t qstate12_prep_mul(qstate12_type *pqs1, qstate12_type *pqs2, uint32_t nqb)
Auxiliary low-level function for function qstate12_product()
Prepare the states
qs1
andqs2
referred bypqs1
andpqs2
for matrix multiplication. Here the summation in that operation runs over firstnqb
qubits ofqs1
andqs2
, regardless of the shape of the input matrices. The function returns a numberrow_pos
, so that, after preparation, the firstnqb
columns of submatricesA1
andA2
of the bit matricesM1
andM2
corresponding toqs1
andqs2
will be equal in the following sense:A1[i,j] = A2[i,j] for i < 'row_pos', j < 'nqb' , A1[i,j] = A2[i,j] = 0 for i >= 'row_pos', j < 'nqb' .Also, matrices
A1
andA2
will both have rankrow_pos - 1
, when excluding row 0 of the two matrices. Some rows ofA1
orA2
may be deleted to achieve this situation. The result of the summation of the matrix products ofqs1
andqs2
over the firstnqb
columns (which is used by the matrix multiplication procedure) is not changed by this operation. Apart from this assertion, both states are changed, and they may have less rows than before. They may even be changed to zero, if the result of the multiplication is zero.The algorithm used here is explained in the API reference in section Multiplication of quadratic mappings. In the notation in that section the algorithm computes states \(\mbox{qs1}', \mbox{qs2}'\) with \( (\mbox{qs1}' \odot \mbox{qs2}')_n = (\mbox{qs1} \odot \mbox{qs2})_n, \), where \( n\) =
nqb
.
pqs1->shape1
andpqs2->shape1
are ignored.
- int32_t qstate12_product(qstate12_type *pqs1, qstate12_type *pqs2, uint32_t nqb, uint32_t nc)
Compute a certain product of two states.
Compute a certain product
qs3
of the statesqs1
andqs2
referred bypqs1
andpqs2
and store the (reduced) result in*pqs1
. Overlap betweenpqs1
andpqs2
is possible.qs2
is not changed.Let
n1 = pqs1->ncols, n2 = pqs2->ncols
. Putqs1a = qstate12_extend(qs, n1, n2-nqb)
,qs2a = qstate12_extend(qs, nqb, n1-nqb)
. Thenqs1a
andqs2a
are complex functions on(nn1 + nn2 - nqb)
bits. Letqs3a
be the complex function which is the product of the functionsqs1a
andqs2a
. Then we haveqs3 = qstate12_sum_cols(qs3a, 0, nc)
.E.g.
qstate12_product(pqs1, pqs2, nc, nc)
is the tensor contraction over the firstnc
qubits ofqs1
andqs2
. In casepqs1->ncols = pqs2->ncols = n
the functionqstate12_product(pqs1, pqs2, n, 0)
returns the product ofqs1
andqs2
(considered as functions). Furthermore, andqstate12_product(pqs1, pqs2, n, n)
returns the scalar product ofqs1
andqs2
(considered as vectors).In general,
qstate12_product(pqs1, pqs2, n, 0)
corresponds to the function \( (\mbox{qs1}' \odot \mbox{qs2}')_n \) defined in section Products and tensor products of quadratic mappings of the API reference.
pqs1->shape1
is set to 0. The user should setpqs1->shape1
to a reasonable value.
- int32_t qstate12_matmul(qstate12_type *pqs1, qstate12_type *pqs2, qstate12_type *pqs3)
Compute the matrix product of two matrices.
Compute the matrix product
qs3
of the maticesqs1
andqs2
referred bypqs1
andpqs2
and store the (reduced) result in*pqs3
. Overlap betweenpqs1, pqs2, pqs3
is possible.If
qs1
has shape(r1,c1)
andqs2
has shape(r2,c2)
thenc1 == r2
must hold, andqs3
has shape(r1,c2)
Note that a shape
(r,c)
of a matrixqs
means a2**r
times2**c
matrix, wherer+c == qs.ncols
,c = qs.shape1
.
- int32_t qstate12_pauli_vector(qstate12_type *pqs, uint64_t *pv)
Check if a matrix is in the Pauli group and convert it to a vector.
The Pauli group of \(n\) qubits is the normal subgroup of the Clifford group of \(n\) qubits generated by the not gates, the phase \(\pi\) gates, and by the scalar multiples of the unit matrix by a fourth root of unity.
We represent an element of the Pauli group as a product of \(2n+2\) generators of order 2 or 4. The sequence of these exponents is stored in a bit vector (coded as an integer) as follows:
Bit 2n+1: a scalar factor sqrt(-1) Bit 2n: a scalar factor -1 Bit n+i: a not gate applied to qubit i, 0 <= i < n Bit i: a phase pi gate applied to qubit i, 0 <= i < nSee section The Pauli group in the API reference for details.
If the matrix
qs
referred bypqs
is in the Pauli group of \(n\) qubits then the function returns \(n\) and storesqs
as an element of the Pauli group in the vectorv
referred bypv
. Otherwise the function returns a negative error code.
- int32_t qstate12_pauli_matrix(qstate12_type *pqs, uint32_t nqb, uint64_t v)
Convert element of the Pauli group to a matrix.
Here parameter
v
encodes an element of the Pauli group ofnqb
qubits as described in function qstate12_pauli_vector(). The function convertsv
to a matrix of shape(nqb, nqb)
in the Clifford group and stores the result in the state referred bypqs
.
- uint64_t qstate12_pauli_vector_mul(uint32_t nqb, uint64_t v1, uint64_t v2)
Multiplication of two elements of the Pauli group.
Here parameters
v1
andv2
encode two elements of the Pauli group ofnqb
qubits as described in function qstate12_pauli_vector().The function returns the product
v1 * v2
encoded in the same way.
- uint64_t qstate12_pauli_vector_exp(uint32_t nqb, uint64_t v, uint32_t e)
Exponentiation of an element of the Pauli group.
Here parameter
v1
encodes an element of the Pauli group ofnqb
qubits as described in function qstate12_pauli_vector().The function returns the power
v1 ** e
encoded in the same way.The Pauli group has exponent 4, so
qstate12_pauli_vector_exp(nqb, v1, 3)
returns the inverse ofv1
.
- int32_t qstate12_reduce_matrix(qstate12_type *pqs, uint8_t *row_table)
Perform a special reduction on a quadratic state matrix.
This function performs a special reduction on the quadratic state matrix
qs
referred bypqs
, as described in the API reference**, section Reducing a quadratic state matrix.This kind of reduction is differnt from the reduction in function qstate12_reduce(). It is used internally for computing traces and norms of matrices. It is also used in function qstate12_pauli_conjugate().
The function also computes a table with
pqs->nrows + pqs->ncols
entries in the array referred by parameterrow_table
which is used internally for the operations mentioned above.
- int32_t qstate12_mat_lb_rank(qstate12_type *pqs)
compute the rank of a quadratic state matrix
Let
qs
be the quadratic state matrix referred bypqs
. The function returns the binary logarithm of the rank of matrixqs
, which is an integer in case of the nonzero matrix. It returns -1 ifqs
is the zero matrix. A return value less than -1 is an error code. Matrixqs
is reduced.
- int32_t qstate12_mat_inv(qstate12_type *pqs)
Compute the inverse of a quadratic state matrix.
Let
qs
be the quadratic state matrix referred bypqs
. The function computes the (reduced) inverse of matrixqs
in place. It returns ERR_QSTATE12_MATRIX_INV if the matrix is not invertible.
- int32_t qstate12_to_symplectic(qstate12_type *pqs, uint64_t *pA)
Convert quadratic state matrix to a symplectic bit matrix.
Here the quadratic state matrix
qs
referred bypqs
must be of shape(k, k)
and invertible. The function computes a2k
times2k
bit matrixA
.If
v
is a bit vector representing an element of the Pauli group thenv * A
represents the elementqs * v * qs^{-1}
of the Pauli group, up to a scalar factor. Elements of the Pauli group ofk
qubits are encoded as in functionqstate12_pauli_vector()
, ignoring the bits at positions2k
and2k + 1
. SopA[i]
will contain the image of thei
-th basis vector of the Pauli group, with bits2k
and2k + 1
set to zero.The function returns
2*k
in case of success and a negative value in case of an error. In any case it suffices if the array referred bypA
has 32 entries.This function can be considered as a simplified version of function
qstate12_pauli_conjugate
. It computes the natural homomorphism from the group of invertible quadratic state matrices shape(k, k)
to the symplectic group \(\mbox{S}_{2k}(2)\).
- int32_t qstate12_to_symplectic_row(qstate12_type *pqs, uint32_t n)
Conjugate unit vector in Pauli group by quadratic state matrix.
Here the quadratic state matrix
qs
referred bypqs
must be of shape(k, k)
and invertible.Let
v
be the bit vector with bitn
set and the other bits cleared. Here elements of the Pauli group ofk
qubits are encoded as in functionqstate12_pauli_vector()
, ignoring the bits at positions2k
and2k + 1
.The function returns the element
qs * v * qs^{-1}
of the Pauli group, up to a scalar factor as an integer, encoded in the same way as input vectorv
, ignoring the scalar factor.Thus in case of success the return value is the same as row
n
of the matrix computes by functionqstate12_to_symplectic_row
. The function returns a negative value in case of an error.
- int32_t qstate12_pauli_conjugate(qstate12_type *pqs, uint32_t n, uint64_t *pv, uint32_t arg)
Conjugate Pauli group elements with a Clifford group element.
Here the quadratic state matrix
qs
referred bypqs
must be of shape(k,k)
and invertible. The arrayv
referred bypv
hasn
entriesv[0],...,v[n-1]
. Each of these entries is interpreted as an element of the Pauli group ofk
qubits, encoded as in functionqstate12_pauli_vector()
.The function replaces
v[i]
by the Pauli group elementw[i] = qs * v[i] * qs**(-1)
for alli < n
.w[i]
is encoded in the same way asv[i]
.Parameter
arg
should usually be a nonzero value. In casearg == 0
the (complex) argument of the outputsv[i]
is not computed.This function uses function
qstate12_reduce_matrix()
. The operation of this function is explained in the API reference, section Reducing a quadratic state matrix .
Computing in the subgroup \(G_{x0}\) of the Monster
The functions in file xsp2co1.c
implement the group operation
of the subgroup
\(G_{x0}\) (of structure \(2^{1+24}.\mbox{Co}_1\))
of the monster.
Represenation of \(G_{x0}\) on the tensor product \(4096_x \otimes \Lambda\)
In [Sey20], section 7.4 and 9, the generators \(x_d, x_\delta, y_\delta, x_\pi, \xi\) of \(G_{x0}\) are also defined as generators of a group \(G_{x1} \subset G(4096_x) \times G(24_x)\). Here \(G(4096_x)\) is a subgroup of the real Clifford group \(\mathcal{C}_{12}\) operating on the 4096-dimensional real vector space \(4096_x\), and \(G(24_x)\) is the automorphism group \(\mbox{Co}_0\) of the Leech lattice \(\Lambda\). \(G_{x1}\) is a preimage of \(G_{x0}\) with \(|G_{x1}:G_{x0}| = 2\), and \(G_{x0}\) operates faithfully on the tensor product \(4096_x \otimes_\mathbb{Z} \Lambda\). Let \((x_g, L_g) \in G_{x1} \subset G(4096_x) \times G(24x)\). Component \(x_g\) determines component \(L_g\) of the pair up to sign. So it suffices to store the image \(v_g = v_0 \cdot L_g\) of a fixed shortest vector \(v_0 \in \Lambda / 3 \Lambda\) instead of the whole automorphism \(L_g\) of \(\Lambda\). We put \(v_0 = (0,0,4,-4,0,...,0)\) in the standard basis of the Leech lattice.
We can reconstruct \(L_g\) from \(x_g\) and
\(v_g\) as follows. \(G(4096_x)\) has an extraspecial
subgroup \(Q_{x1}\) of structure \(2^{1+24}\). The
quotient of \(Q_{x1}\) by its center \(Z(Q_{x1})\) is
isomorphic to \(\Lambda / 2 \Lambda\). By definition of
\(G_{x1}\), the element \(L_g\) operates on
\(\Lambda / 2 \Lambda\) in the same way as \(x_g\)
operates on \(Q_{x1}/Z(Q_{x1})\) by conjugation.
So that operation of \(L_g\) can be reconstructed from
\(x_g\). A short vector in \(\Lambda / 2 \Lambda\)
has precisely two short preimages in \(\Lambda\) which
are opposite. Thus the image of one short vector is known
exactly, and the images of all short vectors are known up to
sign. Since \(L_g\) preserves the scalar product, the
images of all short vectors in \(\Lambda\) can be computed.
Function xsp2co1_elem_to_leech_op
in file xsp2co1.c
constructs \(L_g\) from \(x_g\) and \(v_g\).
The functions in file gen_leech.c
support operations on
\(\Lambda / 2 \Lambda\) and \(\Lambda / 3 \Lambda\).
The \(G_{x0}\) representation
We actually represent an element of \(G_{x0}\) in G_x0
representation. This is as an array elem
of 26 integers
of type uint64_t
. That array contains a pair
\((x_g,v_g)\) as described above with \(v_g\) stored
in the first entry elem[0]
, and \(x_g\) stored in the
remaining 25 entries of array elem
.
Vector \(v_g \in \Lambda / 3 \Lambda\) is stored in
elem[0]
as a 48-bit integer in Leech lattice mod 3
encoding as described in the documentation of module
gen_leech.c
.
We store the inverse \(x_g^{-1}\) of \(x_g\) in
the upper 25 entries of the array elem
. The rationale
for storing the inverse is that this simplifies the operation
of \(G(4096)_x\) on \(Q_{x1}\) by conjugation, using
function qstate12_pauli_conjugate
in file qmatrix12.c
.
Note that \(x_g^{-1} = x_g^\top\), since \(x_g\)
is orthogonal.
In section The subgroup G_{x0} of the Monster and the Clifford group an element \(c\)
of \(\mathcal{C}_{12}\) is given as a real
\(2^{12} \times 2^{12}\) matrix stored in a structure
of type qstate12_type
. In case \(c \in G(4096_x)\)
that matrix has rational entries, where the denominators are
powers of two. A structure of type qstate12_type
representing a \(c \in G(4096_x)\) contains
a triple \((e,A,Q)\). There \(e\) is a signed integral
power of two, and \((A,Q)\) is a pair of bit
matrices with up to 25 rows and up to 49 colums, where the
first 24 columns belong to matrix \(A\), and the remaining
columns belong to matrix \(Q\).
Changing the sign of \(e\) corresponds to negation of a matrix \(x_g^{-1} \in G(4096_x)\) given by \((e,A,Q)\) or to multiplication by \(x_{-1}\). In the group \(G_{x0}\), changing the sign of \(v_g\) has the same effect as changing the sign of \(x_g\); so \(e\) can always be made positive. The absolute value of \(e\) is just there for scaling the operator norm of a matrix \(c\) to 1, and can be omitted.
So we can represent one of the values \(\pm x_g^{-1}\) as a pair \((A,Q)\) with an implied positive scalar factor \(e\) as above, and negate component \(v_g\) of the pair \((x_g,v_g)\), if necessary.
Assuming that \(x_g^{-1}\) is stored in a structure
qs
of type qstate_type
, we copy all valid entries
qs.data[i]
to elem[i+1]
. This amounts to copying the
components \((A,Q)\) of the triple \((e,A,Q)\)
from qs
to elem
. We always reduce the quadratic
state matrix in qs
before copying it, as indicated in
section The subgroup G_{x0} of the Monster and the Clifford group. We fill unused entries
and bits in the array elem
with zeros. Thus the
representation of a \(g \in G_{x0}\) in memory is unique.
qs
can easily be reconstructed from elem
, assuming
that the scalar factor \(e\) in the triple
\((e,A,Q)\) is positive, and that trailing zero
entries in the array elem
are unused.
A word \(w\) in the generators of the subgroup \(G_{x0}\)
of the monster group can be converted to G_x0 representation
by calling function xsp2co1_set_elem_word
in file
xsp2co1.c
. Here the word \(w\) must be given as an array `
of unsigned 32-bit integers as described in section
Header file mmgroup_generators.h.
The normal subgroup \(Q_{x0}\) of \(G_{x0}\)
The group \(G_{x0}\) also has an extraspecial normal subgroup \(Q_{x0}\) of structure \(2^{1+24}\). There is a natural isomorphism between the normal subgroup \(Q_{x1}\) of \(G(4096_x)\) and \(Q_{x0}\). Considering \(G(4096_x)\) and \(G(24_x)\) as matrix groups, this isomorphism is given by:
We identify \(Q_{x0}\) with \(Q_{x1}\). Both groups are generated by elements \(x_d, x_\delta\), as described above.
We also represent an element of \(Q_{x0}\) as a 25-bit integer in Leech lattice encoding as described in section Description of the mmgroup.generators extension.
Changing the basis of the space \(4096_x\)
We also use the vectors \((d'), d \in \mathcal{P}\) as basis vectors of \(4096_x\) , where:
The reason for introducing this basis is that the operation of \(G_{x0}\) on \(Q_{x0}\) (by conjugation) is easy when we use this basis. Then we obviously have \((-d)' = -(d)'\). We can transform the coordinates of a vector \(v\) from the basis given by \(d^\pm\) to the basis given by \((d)'\) by multiplying the coordinate vector with a matrix \(H\). Multiplication with matrix \(H\) is equivalent to applying the Hadamard gate to Qubit 11 (i.e. to the bit with valence \(2^{11}\)) of the coordinates of \(v\) . Thus \(H\) is an involution.
The numbering of the 4096 basis vectors \((d)'\) corresponds to the numbering of the positive elemments of \(\mathcal{P}\). We may put \((d \oplus 2^{12})' = -(d)'\), where \(\oplus\) means bitwise addition modulo 2; then that correspondence holds for all values \(0 \leq d < 2^{13}\). The exact defnition of the operator \(\oplus\) on the Parker loop \(\mathcal{P}\) is given in section Implementing generators of the Monster group.
In this basis the operation of the extraspecial group \(Q_{x0}\) is very simple:
\(x_e x_{\theta(e)}\) maps \((d)'\) to \((d \oplus e)'\) for \(e \in \mathcal{P}\). Here \(\theta\) is the cocycle, see section The Parker loop. In the language of quantum computing this corresponds to a sequence of commuting not gates.
\(x_\epsilon\) maps \((d)'\) to \((-1)^{\langle d, \epsilon\rangle}(d)'\) for \(\epsilon \in \mathcal{C}^*\). Here \(\mathcal{C}^*\) is the Golay cocode. In the language of quantum computing this corresponds to a sequence of commuting phase-\(\pi\) gates.
Since \(H\) is in \(\mathcal{C}_{12}\), it operates on
\(Q_{x0}\) by conjugation. The following subtlety has to be
considered in function conv_pauli_vector_xspecial
(in
file xsp2cco1.c
) implementing that operation.
\(H\) exchanges the anticcommuting
elements of \(Q_{x0}\) of with numbers 0x800
and
0x800000
in Leech lattice encoding. Thus it negates
the element with number 0x800800
.
Converting an element in G_x0 representation to a word of generators
Perhaps the most inportant function in this module is function
xsp2co1_elem_to_word
. This function converts an element of
the subgroup \(G_{x0}\) from G_x0 representation to a
word \(w\) of generators of the monster group. That word
\(w\) is unique and reduced in the sense explained in the
description of that function.
There is also a companion function xsp2co1_reduce_word
that
first converts an arbitrary word in the generators of the
subgroup \(G_{x0}\) of the monster to G_x0 representation.
Then it calls function xsp2co1_elem_to_word
to compute
the reduced word equal to the input word.
We briefly explain the implementation of function
xsp2co1_elem_to_word
. Let \(g \in G_{x0}\) be given in
G_x0 representation. The function first computes the image
\(g^{-1} x_\Omega g\) of \(x_\Omega\) using function
xsp2co1_xspecial_conjugate
, with \(\Omega\) as in
[Sey20]. Using that image and function
gen_leech2_reduce_type4
in file gen_leech.c
we can
compute a word \(w_1\) in the generators of \(G_{x0}\)
such that \(g_1 = g \cdot w_1\) stabilizes
\(x_\Omega\) up to sign.
Then \(g_1\) is in the monomial subgroup \(N_{x0}\) of
\(G_{x0}\) of structure \(2^{1+24}.2^{11}.M_{24}\). For any
\(g_1 \in N_{x0}\) function xsp2co1_elem_monomial_to_xsp
computes a word in the generators of the monster that is equal
to \(g_1\).
Given a monomial element \(g_1\) in G_x0 representation,
function xsp2co1_elem_monomial_to_xsp
computes a word of
generators equal to \(g_1\) as follows.
Ignoring signs and identifying the basis vector \(d_1^+\) of
\(4096_x\) with the basis vector \(d_1^-\), Table 3 in
[Sey20] states that \(x_\pi y_e x_f\) maps
\(d_1^\pm\) to \((d^\pi e f)_1^\pm\). This corresponds
to an affine mapping \(d \mapsto d^\pi e f\) from
\(\mathcal{C} / \langle \Omega \rangle\) to itself, from which
we can easily compute \(e, f\) (modulo sign and \(\Omega\)),
and also \(\pi\). Thus we can find a word \(w_2\) in the
generators \(x_\pi y_e x_f\), such that \(g_2 = g_1 w_2\)
stabilizes all basis vectors of \(4096_x\) up to sign,
and possibly exchanging \(d_1^+\) with \(d_1^-\).
Then \(g_2\) can easily be converted into a word in
the generators
\(x_{-1}, x_\Omega, x_\delta, \delta \in \mathcal{C}^*\).
We use function qstate12_monomial_matrix_row_op
in file
qmatrix12.c
for obtaining the affine mapping
\(d \mapsto d^\pi e f\) from the G_x0 representation
of \(g_1\). We use the functions in file mat24_functions.c
for obtaining \(\pi\) from that affine mapping.
C functions in xsp2co1.c
File
xsp2co1.c
contains functions for computing in the subgroup \(G_{x0}\) (of structure \(2^{1+24}.\mbox{Co}_1\)) of the monster.Functions
- uint64_t xsp2co1_find_chain_short_3(uint64_t v3_1, uint64_t v3_2)
Find vector not orthogonal to vectors in Leech lattice mod 3.
Given two vectors \(v_{3,1}\) and \(v_{3,2}\) in the Leech lattice mod 3, the function returns a vector \(v_{3,3}\) such that the scalar product \(\langle v_{3,3}, v_{3,i} \rangle\) is not zero for both, \(i = 1, 2\). \(v_{3,3}\) has precisely two nonzero coordinates and is hence short. Such a vector \(v_{3,3}\) exists if none of the vectors \(v_{3,1}, v_{3,2}\) is zero. If no such vector \(v_{3,3}\) exists then the function returns 0.
All vectors \(v_{3,i}\) are in given in Leech lattice mod 3 encoding.
- int32_t xsp2co1_chain_short_3(qstate12_type *pqs, uint32_t n, uint64_t *psrc, uint64_t *pdest)
Apply transformation in \(G_{x0}\) to vectors in Leech lattice mod 3.
Let \(x_g \in G(4096_x)\) be given by the quadratic state matrix referred by
pqs
. Letpsrc
be an array \((v_0,\ldots v_{n-1})\) of \(n\) short vectors in the Leech lattice mod 3, given in Leech lattice mod 3 encoding. We try to compute \(w_i = v_i x_g\) for \(0 \leq i < n\) and to store \(w_i\) inpdest[i]
, also in Leech lattice mod 3 encoding. Unfortunately, the short vector \(w_i\) is defined to sign only. In other words, \(x_g\) may correspond to two different elements \(\pm g\) in the automorphisem group \(\mbox{Co}_0\) of the Leech lattice.To specify the correct \(g \in \mbox{Co}_0\), we must store the correct value \(w_0 = v_0 x_0\) in
pdest[0]
and provide short vectors \(v_i\) such that the scalar product \(\langle v_{i-1}, v_i\rangle \) of adjacent vectors is not zero for \(i>0\). The the correct values \(v_i x_i\) are determined by ortohonality of \(g\).The function returns garbage if the input conditions for the \(x_g, v_0, w_0\) are not satisfied. It returns a negative value if two adjacent vectors \(v_0\) are orthognal or not short.
- int32_t xsp2co1_elem_to_qs_i(uint64_t *elem, qstate12_type *pqs)
Get component \(x_g^{-1} \in G(4096_x)\) from \(g \in G_{x0}\).
Let \(g \in G_{x0}\) be stored in the array
elem
, in G_x0 representation. This means that \(g\) is given as a pair \((x_g, v_g) \in G(4096_x) \times \Lambda / 3 \Lambda\) . The function stores \(x_g^{-1}\) in the structureqs
of typeqstate12_type
referred bypqs
.Component \(v_g\) is equal to
elem[0]
(in Leech lattice mod 3 encoding).Caution:
This is a low-level function. After returning, the structure
qs
and the arrayelem
share the same data block.Caution:
Internally, we store the inverse of component \(x_g\) in the element \(g\), and this function also stores that inverse in the structure
qs
.
- int32_t xsp2co1_elem_to_qs(uint64_t *elem, qstate12_type *pqs)
Get component \(x_g \in G(4096_x)\) from \(g \in G_{x0}\).
Let \(g \in G_{x0}\) be stored in the array
elem
, in G_x0 representation. This means that \(g\) is given as a pair \((x_g, v_g) \in G(4096_x) \times \Lambda / 3 \Lambda\) . The function stores \(x_g\) in the structureqs
of typeqstate12_type
referred bypqs
. \(x_g\) represents a \(4096 \times 4096\) matrix.Caution:
The structure referred by
pqs
must provide sufficient memory for data, see functionqstate12_set_mem
in fileqstate12.c
; herepqs->data
should be at least 25.
- int32_t xsp2co1_qs_to_elem_i(qstate12_type *pqs, uint64_t v_g, uint64_t *elem)
Construct \(g \in G_{x0}\) from pair \((x_g, v_g)\).
The function constructs a \(g \in G_{x0}\) as a pair \((x_g, v_g) \in G(4096_x) \times \Lambda / 3 \Lambda\) and stores the result in the array
elem
in G_x0 representation. The value \(x_g^{-1} \in G(4096_x)\) must be given as a structure of typeqstate12_type
referred bypqs
. The value \(v_g \in \Lambda / 3 \Lambda\) must be given by parameterv3
in Leech lattice mod 3 encoding.Caution:
As a low-level function, this function may construct a value \(g\) which is not in \(G_{x0}\). Function
xsp2co1_set_elem_word
should be used for constructing an element of \(G_{x0}\) instead.Caution:
Internally, we store the inverse of component \(x_g\) in the element \(g\), and this function also requires that inverse in the structure referred by
pqs
.
- int32_t xsp2co1_reduce_elem(uint64_t *elem)
Reduce an \(g \in G_{x0}\) to a standard form.
Let \(g \in G_{x0}\) be stored in the array
elem
, in G_x0 representation. This means that \(g\) is stored as a pair \((x_g, v_g) \in G(4096_x) \times \Lambda / 3 \Lambda\) . The function reduces the components \(x_g\), \(v_g\) to their standard form in place.In functions that construct elements of \(G_{x0}\) these components are reduced automatically.
- void xsp2co1_neg_elem(uint64_t *elem)
Negate an \(g \in G_{x0}\).
Let \(g \in G_{x0}\) be stored in the array
elem
, in G_x0 representation. The function negates \(g\) in place.Negation is equivalent to multiplication with the generator \(x_{-1}\), and also to multiplication with the generator \(y_{\Omega}\).
- void xsp2co1_copy_elem(uint64_t *elem1, uint64_t *elem2)
Copy a \(g \in G_{x0}\).
The function copies the element of \(G_{x0}\) stored in the array
elem1
(in G_x0 representation) to the arrayelem2
.
- int32_t xsp2co1_elem_to_bitmatrix(uint64_t *elem, uint64_t *pA)
Map element of \(G_x0\) to a bit matrix.
The function maps the element of \(G_{x0}\)
stored in
the array
elem
(in G_x0 representation) to a \(24 \times 24\) bit matrix \(A\), which will be stored in the array referred bypA
. Bit matrix \(A\) operates on a vector on the Leech lattice modulo 2 (in Leech lattice encoding) by right multiplication.So this function computes the homomorphism from the group \(G_{x0}\) onto the group \({Co}_1\).
- int32_t xsp2co1_mul_elem(uint64_t *elem1, uint64_t *elem2, uint64_t *elem3)
Multiply two elements of the group \(G_{x0}\).
Let \(g_1, g_2 \in G_{x0}\) be stored in the arrays
elem1
,elem2
in G_x0 representation. The function computes \(g_1 \cdot g_2 \) and stores the result in the arrayelem3
in G_x0 representation.Any kind of overlapping beween the arrays
elem1
,elem2
, andelem3
is allowed.
- int32_t xsp2co1_inv_elem(uint64_t *elem1, uint64_t *elem2)
Invert an element of the group \(G_{x0}\).
Let \(g_1 \in G_{x0}\) be stored in the array
elem1
, in G_x0 representation. The function computes \(g_1^{-1}\) and stores the result in the arrayelem2
in G_x0 representation.Any kind of overlapping beween the arrays
elem1
andelem2
is allowed.
- int32_t xsp2co1_conj_elem(uint64_t *elem1, uint64_t *elem2, uint64_t *elem3)
Conjugate elements of the group \(G_{x0}\).
Let \(g_1, g_2 \in G_{x0}\) be stored in the arrays
elem1
,elem2
in G_x0 representation. The function computes \(g_2^{-1} \cdot g_1 \cdot g_2 \) and stores the result in the arrayelem3
in G_x0 representation.Any kind of overlapping beween the arrays
elem1
,elem2
, andelem3
is allowed.
- int32_t xsp2co1_xspecial_conjugate(uint64_t *elem, uint32_t n, uint64_t *ax, uint32_t sign)
Conjugation of elements of \(Q_{x0}\) with an element of \(G_{x0}\).
Let \(x_0,\ldots,x_{n-1}\) a list of \(n\) elements of \(Q_{x0}\) stored in the the array
ax
in Leech lattice encoding. Let \(g \in G_{x0}\) be stored in the arrayelem
in G_x0 representation.Then the function replaces the element \(x_i\) by \(g^{-1} x_i g\) for \(0 \leq i < n\).
Parameter
sign
should usually be a nonzero value. In casesign = 0
the signs of the returned vectors are not computed.
- int32_t xsp2co1_xspecial_img_omega(uint64_t *elem)
Conjugation of \(\Omega\) with an element of \(G_{x0}\).
Let \(g \in G_{x0}\) be stored in the array
elem
in G_x0 representation, and let \(\Omega\) be the standard frame in the Leech latice. The function returns \(g^{-1} \Omega g\) in Leech lattice encoding, ignoring the sign of the result.
- int32_t xsp2co1_elem_check_fix_short(uint64_t *elem1, uint32_t v)
Check if an element of \(G_{x0}\) fixes a short vector.
This function is deprecated!
Let \(v\) be the short vector in the Leech lattice modulo 2 given by parameter
v
in Leech lattice encoding. Let \(g \in G_{x0}\) be stored in the arrayelem
in G_x0 representation.If \(v\) is short then it corresponds to a vector \(v'\) in the 24-dimensional Leech lattice \(\Lambda\) up to sign. Note that the operation of \(G_{x0}\) on \(\Lambda\) is also defined up to sign only. So in the general case we cannot distinguish whether \(g\) fixes or negates \(v'\).
However, \(G_{x0}\) has a (faithful) representation on the tensor product \(\Lambda \otimes 4096_x\) for a certain representation \(4096_x\), see [Con85] for details. Here the operation of \(G_{x0}\) on \(4096_x\) is also defined up to sign only.
If the character of \(g\) on \(4096_x\) is nonzero then we can flip the signs in both representations, \(\Lambda\) and \(4096_x\), without changing the tensor product. Thus requiring the character of \(g\) on \(4096_x\) to be positive determines the sign of the operation of \(g\) on \(\Lambda\) uniquely. In this case we return 0 if \(g\) fixes the vector \(v'\), and 1 if \(g\) negates \(v'\). Otherwise we return 6.
If the character of \(g\) on \(4096_x\) is zero then there is no way to determine the sign of the operation of \(g\) on \(\Lambda\). In this case we return 2 if \(g\) fixes the vector \(v'\) (up to sign) and 6 otherwise.
In cases where \(g\) and \(-g\) are in different classes in \(G_{x0}\) we may sometimes obtain the class of \(g\) by using this function.
We return a negative value in case of any error. It is an error if \(v'\) is not short, i.e. \(v\) is not of type 2.
- int32_t xsp2co1_xspecial_vector(uint64_t *elem)
Convert \(x \in Q_{x0}\) from \(G_{x0}\) rep to Leech.
Let \(x \in Q_{x0} \subset G_{x0}\) be stored in the array
elem
in G_x0 representation. The function returns \(x\) as an integer in Leech lattice encoding.The function returns a negative number in case of error. E.g. in case \(x \notin Q_{x0}\) it returns
ERR_QSTATE12_NOTIN_XSP
.
- void xsp2co1_unit_elem(uint64_t *elem)
Store neutral element of \(G_{x0}\).
The function stores the neutral element of \(G_{x0}\) in the array
elem
in G_x0 representation.
- uint32_t xsp2co1_is_unit_elem(uint64_t *elem)
Check if
elem
is neutral element of \(G_{x0}\).The function returns 1 if
elem
is the neutral element of \(G_{x0}\) and 0 otherwise.
- int32_t xsp2co1_elem_xspecial(uint64_t *elem, uint32_t x)
Convert \(x \in Q_{x0}\) from Leech to \(G_{x0}\) rep
Let \(x \in Q_{x0} \subset G_{x0}\) be stored in parameter
x
in Leech lattice encoding. The function converts \(x\) to G_x0 representation and stores the result in the arrayelem
.
- int32_t xsp2co1_mul_elem_word(uint64_t *elem, uint32_t *a, uint32_t n)
Right multiply an element of \(G_{x0}\) with a word of generators.
Let \(g \in G_{x0}\) be stored in the array
elem
in G_x0 representation. We replace \(g\) by \(g \cdot w\), where \(w\) is a word in the generators of \(G_{x0}\) of length \(n\). \(w\) is stored in the arraya
, and each entry ofa
encodes a generator of \(G_{x0}\) as described in filemmgroup_generators.h
.The function fails and returns ERR_QSTATE12_GX0_TAG if not all atoms of the word \(w\) are in \(G_{x0}\).
- int32_t xsp2co1_set_elem_word(uint64_t *elem, uint32_t *a, uint32_t n)
Convert word of generators of \(G_{x0}\) to G_x0 representation.
Let \(w\) be a word in the generators of \(G_{x0}\) of length \(n\). \(w\) is stored in the array
a
, and each entry ofa
encodes a generator of \(G_{x0}\) as described in filemmgroup_generators.h
. We convert the word \(w\) to an element of \(G_{x0}\) in G_x0 representation and store the result in the arrayelem
.The function fails and returns ERR_QSTATE12_GX0_TAG if not all atoms of the word \(w\) are in \(G_{x0}\).
- int32_t xsp2co1_mul_elem_atom(uint64_t *elem, uint32_t v)
Right multiply an element of \(G_{x0}\) with a generator.
Equivalent to
xsp2co1_mul_elem_word(elem, &v, 1)
- int32_t xsp2co1_set_elem_atom(uint64_t *elem, uint32_t v)
Convert a generator of \(G_{x0}\) to G_x0 representation.
Equivalent to
xsp2co1_set_elem_word(elem, &v, 1)
- int32_t xsp2co1_set_elem_word_scan(uint64_t *elem, uint32_t *a, uint32_t n, uint32_t mul)
Convert word of generators of \(G_{x0}\) to G_x0 representation.
Parameters and operation are as in function
xsp2co1_set_elem_word
. But in contrast to functionxsp2co1_set_elem_word
, this function succeeds also if just a prefix of the worda
is in the subgroup \(G_{x0}\).Let
k
be the greatest number such that all prefixes ofa
of length at mostk
are in the group \(G_{x0}\). Let \(a_k\) be the element of \(G_{x0}\) corresponding to the prefix ofa
of lengthk
.If parameter
mul
is zero then we convert the word \(a_k\) to an element of \(G_{x0}\) in G_x0 representation and store the result in the arrayelem
. Otherwise we multiply the elementelem
with the word \(a_k\) and store the array inelem
.
C functions in xsp2co1_word.c
File
xsp2co1_word.c
contains additional functions for computing in the subgroup \(G_{x0}\) (of structure \(2^{1+24}.\mbox{Co}_1\)) of the monster. This file can be considered as a supplement to filexsp2co1.c
.Functions
- uint64_t xsp2co1_to_vect_mod3(uint64_t x)
Auxiliary function for function
xsp2co1_add_short_3_leech
The function converts a vector in \(\Lambda / 3\Lambda\) from Leech lattice mod 3 encoding to the encoding to the encoding of a vector in \((\mathbb{Z} / 3\mathbb{Z})^{24}\) used in the
mmgroup.mm_op
extension.
- uint64_t xsp2co1_from_vect_mod3(uint64_t x)
Inverse of function
xsp2co1_to_vect_mod3
The function converts a vector in \(\Lambda / 3\Lambda\) from the encoding of a vector in \((\mathbb{Z} / 3\mathbb{Z})^{24}\) used in the
mmgroup.mm_op
extension to the Leech lattice mod 3 encoding.
- int32_t xsp2co1_elem_to_leech_op(uint64_t *elem, int8_t *pdest)
Get Leech lattice matrix from \(g \in G_{x0}\).
Let \(g \in G_{x0}\) be stored in the array
elem
, in G_x0 representation. \(G_{x0}\) operates faithfully on the space \(4096_x \otimes_\mathbb{Z} \Lambda\). This function constructs a \(24 \times 24\) integer matrix \(L_g\) such that \(\frac{1}{8} L_g\) corresponds to the operation of \(g\) on \(\Lambda\). It stores entry \(L_g[i,j]\) indest[24*i+j]
. Matrix \(L_g\) is unique up to sign.Function
xsp2co1_elem_to_qs(elem,...)
computes a (representation of) an orthogonal \(4096 \times 4096\) matrix \(x_g\) such that right multiplication with the Kronecker product \(\frac{1}{8} x_g \otimes L_g\) is equal to the action of \(g\) on \(4096_x \otimes \Lambda\).
- int32_t xsp2co1_short_3_to_leech(uint64_t x, int8_t *pdest)
Compute integral short Leech lattice vector from vector mod 3.
Given a short Leech lattice vector
x
(modulo 3) in Leech lattice mod 3 encoding, the function computes the real coordinates of vectorx
in the array referred bypdest
.pdest
must have length 24. As usual, the norm (i.e. the squared sum of the coordinates) of the computed short vector is normalized to 32.The function returns 0 if
x
encodes a short Leech lattice vector mod 3 and a negative value otherwise.
- int32_t xsp2co1_short_2_to_leech(uint64_t x, int8_t *pdest)
Compute integral short Leech lattice vector from vector mod 2.
Given a short Leech lattice vector
x
(modulo 2) in Leech lattice encoding, the function computes the real coordinates of vectorx
in the array referred bypdest
.pdest
must have length 24. As usual, the norm (i.e. the squared sum of the coordinates) of the computed short vector is normalized to 32. Note that the result is defined up to sign only. Here the function chooses an arbitrary sign.The function returns 0 if
x
encodes a short Leech lattice vector mod 2 and a negative value otherwise.
- int32_t xsp2co1_elem_monomial_to_xsp(uint64_t *elem, uint32_t *a)
Map monomial element of \(G_{x0}\) to element of \(Q_{x0}\).
Let \(g \in G_{x0}\) stored in the array
elem
. The matrix corresponding to \(g\) in the representation \(4096_x\) must be monomial. The function computes a word \(w\) of in the generators of \(G_{x0}\) such that \(g w \in Q_{x0}\). The word \(w\) has length at most 2 and is stored in the arraya
. Each entry ofa
encodes a generator of \(G_{x0}\) as described in filemmgroup_generators.h
. The function returns the length of that word.The atoms in the word have tags
p, y
in that order. Each word is stored as the inverse of a generator.
- int32_t xsp2co1_elem_to_word(uint64_t *elem, uint32_t *a)
Convert element of \(G_{x0}\) to a word in its generators.
Let \(g \in G_{x0}\) be stored in the array
elem
. The function converts \(g\) to a reduced word in the generators of \(g\) and stores that word in the arraya
. Then each entry ofa
encodes a generator of \(G_{x0}\) as described in filemmgroup_generators.h
. The function returns the length of that word.The reduced word stored in the array
a
may have up to 10 entries. The tags of the entries in that word arexdyplplplp
in that order. See documentation of classmmgroup.MMGroup
for the meaning of these tags. Each entry of a word may encode the neutral element as a generator; then that entry is dropped. We assert that the number of entries with tagl
is minimal.
- int32_t xsp2co1_reduce_word(uint32_t *a, uint32_t n, uint32_t *a1)
Reduce a word of generators of \(G_{x0}\).
Let \(g \in G_{x0}\) be stored in the array
a
as a word \(w\) of length \(n\). The function computes the reduced word \(w_1\) equal to \(w\) in the arraya1
and returns the length of the reduced word. Legal tags for the word \(w\) ared
,x
,y
,p
, andl
. See documentation of classmmgroup.MMGroup
for the meaning of these tags.It uses function
xsp2co1_elem_to_word
for computing \(w_1\). The word \(w_1\) stored in the arraya1
may have up to 10 entries. Arraysa
anda1
may overlap.
- int32_t xsp2co1_elem_subtype(uint64_t *elem)
Return the subtype of an element of \(G_{x0}\).
Let \(g \in G_{x0}\) be stored in the array
elem
. The function returns the subtype of \(g\). If \(g\) maps the standard frame \(\Omega\) of the Leech lattice modulo 2 to a frame of subtype \(t\) then \(g\) has subtype \(t\).The subtype is returned as an integer as in function
gen_leech2_subtype
in modulegen_leech.c
.Since the subtype is determined by the size of the denominators of the representation \(4096_x\), it can be computed very fast.
The function returns -1 in case of an error.
- uint32_t xsp2co1_check_word_g_x0(uint32_t *w, uint32_t n)
Check if a word of generators of the monster is in \(G_{x0}\).
We check if the word
w
of lengthn
of generators of the monster group is in the subgroup \(G_{x0}\). The function returns the following status information:0:
w
is in \(G_{x0}\)1:
w
is not in \(G_{x0}\)2: Nothing is known about
w
Words of generators of the monster are implemented as described in file
mmgroup_generators.h
.
- int32_t xsp2co1_isotropic_type4(uint32_t v, uint64_t *pB, int32_t n)
Compute maximal isotropic space corresponding to a type-4 vector.
Any type-4 vector in the Leech lattice mod 2 corrsponds to a unique maximal isotropic space (of dimension 12) in the Leech lattice mod 2. E.g. the standard type-4 vector \(\Omega\) corresponds to the space spanned by \(\Omega\) and (the images in the Leech lattice mod 2 of) all even Golay cocode words.
Given a type-4 vector \(v\) in Leech lattice encoding, we usually want to find the intersection of the isotropic space \(v^{(\perp)}\) corresponding to \(v\) with a given linear subspace \(X\) of the Leech lattice mod 2. Let \(X\) be the space spanned by the vectors \(b_0,...,b_{n-1}\) in the array
B
referred bypB
of sizen
.The function modifies the basis in the array
B
, so that it will be the a basis of the space \(v^{(\perp)} \cup X\) of dimensionm
in reduced echelon form. The function returnsm
in case of success and a negative value in case of failure. The function fails if \(v\) is not of type 4.In case \(n < 0\) we assume that
B
is a basis of the whole Leech lattice mod 2 and return a basis of \(v^{(\perp)}\) inB
. ArrayB
must have size at least \(\max(n, 12)\).
- int32_t xsp2co1_elem_row_mod3(uint64_t *elem, uint32_t column, uint64_t *v)
A low-level function to be used for testing.
A projection matrix \(\Pi\) is a symmetric matrix with one eigenvalue 1 and the other eigenvalues equal to zero operating on an Euclidean vector space. Let \(g \in G_{x0}\) be stored in the array
elem
in G_x0 representation. This function left multiplies \(g\) by a certain projection matrix \(\Pi\). The result \(y = \Pi \cdot g\) is an element of the vector space \(4096_x \otimes 24_x\). The function reduces the coordinates of \(y\) modulo 3 and stores the result in the arrayv
in a format compatible the format used in themmgroup.mm_op
extension.Right multiplcation of \(g\) by \(G_{x0}\) commutes with left multiplication of \(g\) by \(\Pi\), so that we can test the right multiplication by \(G_{x0}\) implemented in this module against the corresponding multiplication implemented in the
mmgroup.mm_op
extension. This leads to the important interoperability test in the python functionmmgroup.tests.test_clifford.test_xs1_vector.test_vector
.We specify the projection matrix \(\Pi\) as a tensor product \(\Pi_{4096} \otimes \Pi_{24}\). Here \(\Pi_{24}\) projects onto the fixed short Leech lattice vector \((0,0,1,-1,0, \ldots,0)\). \(\Pi_{4096}\) is the projection onto the coordinate with number
column
of the space \(4096_x\).Remark:
The result is an array with 4096 entries corresponding to the entries with tags
Z
andY
of a vector in the represention \(\rho_3\), as described in section The Representation of the Monster Group of the API reference.Warning:
This function works only if the data type
uint_mmv_t
used in themmgroup.mm_op
extension is equal to the data typeuint64_t
.
- int32_t xsp2co1_elem_read_mod3(uint64_t *v, uint64_t *elem, uint32_t row, uint32_t column)
Read entry of a transfromed vector of the monster rep modulo 3.
Let \(g \in G_{x0}\) be stored in the array
elem
. Let \(v\) be the vector of the representation \(4096_x \otimes 24_x\) modulo 3 stored in the arrayv
in a format compatible to the format used in themmgroup.mm_op
extension. Then the function returns the entry of the vector \(v' = v \cdot g^{-1}\) in row0 <= row < 4096
and column0 <= column < 24
of \(v'\).This function is considerably faster than the computation of \(v' = v \cdot g^{-1}\) using the functions in the
mmgroup.mm_op
extension.In case
column = 24
the function returns the value(v'[row,2] - v'[row,3]) mod 3
. In case of success the return value is a nonnegative integer less than 3. A negative return value indicates failure.
C functions in xsp2co1_elem.c
File
xsp2co1_elem.c
contains functions for analyzing elements of the subgroup \(G_{x0}\) (of structure \(2^{1+24}.\mbox{Co}_1\)) of the monster.Functions
- int32_t xsp2co1_elem_to_N0(uint64_t *elem, uint32_t *g)
Convert element of \(G_{x0}\) to element of \(N_{0}\).
Let \(g \in G_{x0}\) be stored in the array
elem1
in G_x0 representation. The function converts \(g\) to an element \(N_0\), as described in the documentation of filemm_group_n.c
. The result is stored in the array of length 5 referred by parameterg
.The function returns 0 in case of success and
ERR_QSTATE12_GX0_BAD_ELEM
if \(g\) is not and \(N_0\).
- int32_t xsp2co1_elem_from_N0(uint64_t *elem, uint32_t *g)
Convert element of \(N_{0}\) to element of \(G_{x0}\).
Let \(g \in N_{0}\) be stored in the array of length 5 referred by parameter
g
as described in the documentation of filemm_group_n.c
. We convert \(g\) to an element in G_x0 representation and store the result in the arrayelem
.The function returns 0 in case of success and
ERR_QSTATE12_GX0_BAD_ELEM
if \(g\) is not in \(G_{x0}\).
- int32_t xsp2co1_conjugate_elem(uint64_t *elem, uint32_t *a, uint32_t n)
Conjugate element of \(G_{x0}\) by an element of monster group.
Let \(g \in G_{x0}\) be stored in the array
elem
in G_x0 representation. Let \(w\) be a word in the generators of the monster group of lengthn
. \(w\) is stored in the arraya
, and each entry ofa
encodes a generator of the monster group described in filemmgroup_generators.h
.The function tries to replace \(g\) by \(h = w^{-1} g w\). The function succeeds if for any prefix \(w_i\) of the word \(w\) we have \(w_i^{-1} g w_i \in G_{x0}\).
- int32_t xsp2co1_power_elem(uint64_t *elem1, int64_t e, uint64_t *elem2)
Exponentiation of an element of the group \(G_{x0}\).
Let \(g \in G_{x0}\) be stored in the array
elem1
in G_x0 representation. The function computes the power \(g^e\) and stores the result in the arrayelem2
in G_x0 representation. Here \(-2^{63} < e < 2^{63}\) must hold.A negative return value indicates an error.
Any kind of overlapping beween the arrays
elem1
andelem2
is allowed.
- int32_t xsp2co1_power_word(uint32_t *a1, uint32_t n, int64_t e, uint32_t *a2)
Exponentiation of an word of the group \(G_{x0}\).
Let \(w\) be a word in the generators of \(G_{x0}\) of length
n
. \(w\) is stored in the arraya1
, and each entry ofa1
encodes a generator of \(G_{x0}\) as described in filemmgroup_generators.h
.The function stores \(w^e\) in the array
a2
in the same format as the word \(w\) and returns the length of the computed word, which is at most 10.A negative return value indicates an error.
Any kind of overlapping beween the arrays
a1
anda2
is allowed.
- int32_t xsp2co1_odd_order_bitmatrix(uint64_t *bm)
Compute odd part of the order of an element of \(\mbox{Co}_1\).
Let an element \(g\) of \(\mbox{Co}_1\) be given as a 24 times 24 bit matrix in the array
bm
acting on the Leech lattice modulo 2 by right multiplication. Here vectors in the Leech lattice modulo 2 are given in Leech lattice encoding.Then the function returns the odd part of the order of \(g\). It returns a negative value in case of failure.
- int32_t xsp2co1_half_order_elem(uint64_t *elem1, uint64_t *elem2)
Compute (halved) order of an element of the group \(G_{x0}\).
Let \(g \in G_{x0}\) be stored in the array
elem1
in G_x0 representation. The function returns the order of the element \(g\).If the order \(o\) of \(g\) is even then the function stores \(g^{o/2}\) in the array
elem2
in G_x0 representation. Otherwise it stores the neutral element inelem2
.A negative return value indicates an error.
Any kind of overlapping beween the arrays
elem1
andelem2
is allowed.
- int32_t xsp2co1_order_elem(uint64_t *elem)
Compute order of an element of the group \(G_{x0}\).
Let \(g \in G_{x0}\) be stored in the array
elem1
in G_x0 representation. The function returns the order of the element \(g\).A negative return value indicates an error.
- int32_t xsp2co1_half_order_word(uint32_t *a1, uint32_t n, uint32_t *a2)
Compute (halved) order of a word of the group \(G_{x0}\).
Let \(w\) be a word in the generators of \(G_{x0}\) of length
n
. \(w\) is stored in the arraya1
, and each entry ofa1
encodes a generator of \(G_{x0}\) as described in filemmgroup_generators.h
.If the order \(o\) of the word \(w\) is even then the function stores \(w^{o/2}\) in the array
a2
in the same format as the word \(w\). Otherwise it stores the empty word ina2
. The lengthk
of the word ina2
is at most 10.The function returns the value
0x100 *o + k
.A negative return value indicates an error.
- int32_t xsp2co1_order_word(uint32_t *a, uint32_t n)
Compute order of a word of the group \(G_{x0}\).
Let \(w\) be a word in the generators of \(G_{x0}\) of length
n
. \(w\) is stored in the arraya
, and each entry ofa
encodes a generator of \(G_{x0}\) as described in filemmgroup_generators.h
.The function returns the order of \(w\) .
A negative return value indicates an error.
- uint32_t xsp2co1_leech2_count_type2(uint64_t *a, uint32_t n)
Count type-2 vectors in an affine subspace of the Leech lattice mod 2.
This function returns the number of type-2 vectors in an affine subspace \(V\) of the Leech lattice mod 2. Subspace \(V\) is defined by an array \(a\) of length \(n\) of bit vectors. \(V\) is given by:
\(V = \{a_0 + \sum_{i=1}^{n-1} \lambda_i a_i \mid \lambda_i=0,1\}\).
Caution:
The function may change the description of the affine space \(V\) in the array \(a\) to a different description of the same space \(V\).
Remark:
This function is a much faster version of the function
gen_leech2_count_type2
in filegen_leech.c
. The implementation of the latter function is much simpler; so we keep it for test purposes.
- int32_t xsp2co1_trace_98280(uint64_t *elem, int32_t (*f_fast)(uint64_t*))
Compute character of \(\rho_{98280}\) of element of \(G_{x0}\).
This function is for internal use only.
Let \(g \in G_{x0}\) be stored in the array
elem
in G_x0 representation. The function returns the character of the representation \(\rho_{98280}\).This function may takes a long time is it does not use precomputed tables. However, precomputing such tables may requires this function (being alled without any precomputed tables).
In parameter
f_fast
the user may specify a function with signatureint32_t (*f_fast)(uint64_t *elem)
that returns the character \(\rho_{98280}\) in some cases. That function should use precomputed tables for computing that character and return an error code if it cannot compute a character. In this case we use the standard method form computing the requested character. Iff_fast
isNULL
then we always use the standard method.Any value less than -0x1000000 returned by function
f_fast
or by this function is to be interpreted as an error.
- int32_t xsp2co1_traces_small(uint64_t *elem, int32_t *ptrace)
Workhorse for function
xsp2co1_traces_all
This function is for internal use only.
Parameters and operation are are as in function
xsp2co1_traces_all
. But this function does not compute the character of the representation \(\rho_{98280}\) inptrace[3]
.
- int32_t xsp2co1_traces_all(uint64_t *elem, int32_t *ptrace)
Compute relevant characters of element of \(G_{x0}\).
This function is for internal purposes only.
Let \(g \in G_{x0}\) be stored in the array
elem
in G_x0 representation. The function computes the characters of the representations \(\rho_{24}, \rho_{576}, \rho_{4096}, \rho_{98280}\) and stores the result inptrace[0],..., ptrace[3]
in that order.This function returns 0 in case of success and a nonzero value otherwise.
There is a considerably faster function
xsp2co1_traces_all
in modulexsp2co1_traces.c
performing exactly the same operation depending in the same input parameters. More details are given in the documentation of that function.In contrast to function
xsp2co1_traces_fast
, this function does not use any precomputed tables. Actually, this function is used for precomputing those tables.
- int32_t xsp2co1_rand_word_N_0(uint32_t *w, uint32_t in_N_x0, uint32_t even, uint64_t *seed)
Generate a random element of the group \(N_0\).
The function computes a uniform distributed random element \(g\) of the subgroup \(N_0\) of structure \(2^{2+11+22}.(M_{24} \times \mbox{Sym}_3)\) of the monster. The group \(N_0\) is generated by the generators with tags
x, y, d, p, t
.Thw function stores a word representing the element \(g\) in the buffer
w
and returns the length of that word.The length of the word in the buffer
w
is at most 5.If parameter
in_N_x0
is nonzero then we compute a random element of the subgroup \(N_{x0}\) of index 3 in \(N_0\) generated by the generators with tagsx, y, d, p
.If parameter
even
is nonzero then we compute a random element of the subgroup \(N_{\mbox{even}}\) of index 2 in \(N_{0}\) generated by the generators with tagsx, y, d, p, t
, where all generators with tagd
correspond to even Golay cocode words.If both,
in_N_x0
andeven
, are nonzero then we compute a random element of \(N_{xyz0} = N_{\mbox{even}} \cap N_{x0}\).The function uses the internal random generator in file
gen_random.c
. Parameterseed
must be a seed for a random generator as described in filegen_random.c
.
- int32_t xsp2co1_rand_word_G_x0(uint32_t *w, uint64_t *seed)
Generate a random element of the group \(G_{x0}\).
The function computes a uniform distributed random element \(g\) of the group \(G_{x0}\). It stores a word representing the element \(g\) in the buffer
w
and returns the length of that word.The length of the word in the buffer
w
is at most 10.The function uses the internal random generator in file
gen_random.c
. Parameterseed
must be a seed for a random generator as described in filegen_random.c
.A negative return value indicates an error.
C functions in leech3matrix.c
File
leech3matrix.c
contains functions for computing with matrices corresponding to the part with tag ‘A’ of a vector of the representation of the monster modulo 3. Note that this part has a natural interpretation as a symmetric matrix on the Leech lattice.For these computations we deal with
i0
timesi1
matricesm
fori0 <= 24
,i1 <= 48
, Such a matrix is stored in an arraya
of integers of typeuint64_t
of length 24 * 3. Here the entrym[i,j]
is stored ina[3*i + j/16]
, bits4 * (j % 16),..., 4 * (j % 16) + 3
. We calla
the matrix mod 3 encoding of the matrixm
.Unless otherwise stated, we assume that the lower two bits of such a bit field have arbitrary values, and that the higher two bits of that bit field are zero.
There are functions for loading such a matrix
m
from a vector in a represenation of the monster, for elechonization ofm
, for computing the kernel ofm
etc.Functions
- void leech3matrix_echelon(uint64_t *a)
Echelonize a matrix of integers mod 3.
Here
a
is a matrix in matrix mod 3 encoding as documented in the header of this file. That matrix is transformed to row echelon form. We echelonize columns 0,…,23 of matrixa
in that order. The matrix is not converted to reduced echelon form.
- void leech3matrix_compress(uint64_t *a, uint64_t *v)
compress a matrix in matrix mod 3 encoding
Let
a
be an 24 times 48 matrix in matrix mod 3 encoding. We considera
as a pair of two matricesAh, Al
, withAl
in columns 0,…,23 andAh
in columns 24,…,47 ofa
.We store matrix
Al
in the entriesv[0], ..., v[23]
, and matrixAh
in the entriesv[24], ..., v[47]
. Here columnj
of a row ofAh
orAl
is reduced modulo 3 (so it has value 0, 1, or 2) and that value is stored in bits2*j+1
and2*j
of the corresponding entry ofv
.So each of the matrices
Al
andAh
will be encoded as the part with tag ‘A’ of a vector in the representation \(\rho_3\) of the monster modulo 3.The overlapping
v == a
is legal; any other kind of overlappig betweenv
anda
is illegal.
- void leech3matrix_sub_diag(uint64_t *a, uint64_t diag, uint32_t offset)
Subtract diagonal matrix from matrix in matrix mod 3 encoding.
Let
a
be an 24 times 48 matrix in matrix mod 3 encoding.We subtract a diagonal matrix from
a
. More precisely, we subtract the integerdiag
from all entriesa[i, i+offset]
, fori = 0,...,23
.
- uint64_t leech3matrix_rank(uint64_t *a, uint32_t d)
Rank and kernel of a
24 times 24
matrix modulo 3.Let
r
be the rank of the24 times 24
matrixb = a - d * 1
. Here the entries of that matrix are taken modulo 3,d
is an integer, and1
is the unit matrix. Inputa
is a 24 times 24 matrix in matrix mod 3 encoding as documented in the header of this file.Let
r
be the rank of matrixb
with entries taken modulo 3. If matrixb
has rank 23 then its kernel is one dimensional. In that case the kernel contains two nonzero vectors+-w
, and we definew
to be one of these vectors. Otherwise we letw
be the zero vector.The function returns the value
(r << 48) + w
, withw
the vector defined above given in Leech lattice mod 3 encoding as described in The C interface of the mmgroup project.Input
a
is destroyed.
- uint64_t leech3matrix_vmul(uint64_t v, uint64_t *a)
Multiply vector with a
24 times 24
matrix modulo 3.Input
a
is a 24 times 24 matrix encoded as the part with tag ‘A’ of a vector in the representation \(\rho_3\) of the monster modulo 3. Inputv
is a vector of 24 integers modulo 3 encoded in Leech lattice mod 3 encoding. The function computes the product \(v \cdot a\) of the vector \(v\) and the matrix \(a\) and returns the result in Leech lattice mod 3 encoding.Vector \(v\) has 24 entries. If the upper \(k\) entries of \(v\) are zero then we access the first \(24-k\) rows of matrix \(a\) only. So the buffer referred by
a
must have length (24 - k) in this case.
- int32_t leech3matrix_prep_type4(uint64_t *a, uint32_t n, uint64_t *w, uint64_t *seed)
Prepare subspace of Leech lattice mod 3 for finding type-4 vectors.
Let \(a\) be the subspace of the Leech lattice mod 3 spanned by the vectors in the array
a
of lengthn
. Here each entry of the arraya
is encoded in the same way as a row of the part with tag ‘A’ of a vector in the representation \(\rho_3\) of the Monster modulo 3. Usually, such a subspace of the Leech lattice mod 3 is computed by applying functionleech3matrix_echelon
to a (suitably modified) part with tag ‘A’ of a vector in the representation \(\rho_3\).The function computes an array of
2*n
random vectors taken from the space \(a\) and stores these2*n
vectors in the arrayw
in Leech lattice mod 3 encoding. Half of the vectors in arrayw
are obtained by left multiplying matrix \(a\) with a random upper triangular matrix; and the other half of these vectors is obtained by left multiplication with a random lower triangular matrix. Parameterseed
points to a random generator for generating random matrices; see modulegen_random.c
for details.Thus the vectors in array
w
span the space \(a\); and we may obtain random vectors in \(a\) by performing random additions and subtractions of the entries ofw
. E.g. functionleech3matrix_prep_type4
generates random type-4 in the space space \(a\) using that method.The function returns the size
2*n
of the arrayw
in case of success and a negative value in case of failure. Any overlapping between the arraysa
andw
is allowed. On input,1 <= n <= 12
must hold.
- int32_t leech3matrix_rand_type4(uint64_t *w, uint32_t n, uint32_t trials, uint64_t *seed)
Random type-4 vector in subspace of Leech lattice mod 3.
The function tries to find a random type-4 vector in a subspace \(a\) of the Leech lattice mod 3 spanned by the vectors in the array
a
of lengthn
. Here the entries of the arrayw
should be given in Leech lattice mod 3 encoding, as e.g. returned by functionleech3matrix_prep_type4
. That function returns more vectors generating the space \(a\) than necessary in order to facilitate the generation of random vectors in \(a\).The function performs up to
trials
random additions or subtractions in the space \(a\), until it finds a type-4 vector. If such a type-4 vector has been found then that vector is returned as a vectorv
in the Leech lattice mod 2 in Leech lattice encoding. Parameterseed
points to a random generator for generating the required random data; see modulegen_random.c
for details.If a type-4 vector
v
has been found then the function returns(t << 4) + v
. Here0 <= v < 0x1000000
is the vector found in the Leech lattice mod 2 in Leech lattice encoding; andt
is the number of trials required to findv
. In caset > 127
we putt = 127
.If no type-4 vector has been found after
trials
trials then the function returns 0.The function returns a negative value in case of failure; e.g. if the random generator has failed.
- int32_t leech2matrix_add_eqn(uint64_t *m, uint32_t nrows, uint32_t ncols, uint64_t a)
Add an equation to a system of linear bit equations.
The idea behind this function is that an external process generates rows of a bit matrix with
ncols
columns, with0 < ncols <= 32
. This function checks such a rowa
and accepts it, if it linearly independent of all previously accepted rows. Thus at mostncols
rows can be accepted. Thenrows
already accepted rows are stored in the arraym
. The function returns1
if rowa
is accepted and0
otherwise. A negative return value indicates an error. The size of the arraym
should be at leastncols
.Let
A
be thencols
timesncols
matrix of all accepted rowsa[i]
,0 <= i < ncols
; and letI
be thencols
timencols
unit matrix. We left multiplyA
with a matrixT
such thatT * A = I
. ThusT = A**(-1)
. Technically, we perform row operations on the matrixA[:nrows]
containing the firstnrows
lines already accepted, such thatT * A[:rnows]
is in reduced echelon form. We also perform the same row operations on the unit matrix to obtainT
. We storeT[:rnows]
in columns0,...,ncols-1
of matrixM
andT*A[:rnows]
in columnsncols,...,2*ncols-1
of matrixM
.One may use function
leech2matrix_solve_eqn
for solving a system of linear equations obtained in that way.
- uint32_t leech2matrix_solve_eqn(uint32_t *m, uint32_t ncols, uint64_t v)
Solve a system of linear bit equations.
Let
A
be a nonsingularncols
timesncols
bit matrix stored in the arraym
in the special form as described in functionleech2matrix_add_eqn
.The function returns the solution
w
of the equationw * A = v
.Caution:
Here
m
is of of typeuint32_t *
, but the corresponding parameter in functionleech2matrix_add_eqn
is of typeuint64_t *
. This simplifies the use of this function in most pplications.
- uint32_t leech2_matrix_basis(uint32_t *v2, uint32_t n, uint64_t *basis, uint32_t d)
Subspace generated by vectors of Leech lattice modulo 2.
Compute a basis of the subspace of the Leech lattice modulo 2 generated by the vectors
v2[0],...,v2[n-1]
.The function returns the dimension
k
of that subspace and computes a basis of that subspace inbasis[i], 0 <= i < k
.Here
d
must be an upper bound for the dimensionk
. Ifk
is unknown, one should putd = 24
.Bits 23,…,0 of the output matrix are echelonized in a special way. Here the columns are processed in the order:
11, 22, 21, …, 13, 12, 10, 9, …, 1, 0, 23.
One of the advantages of this echelonization is that the vector \(\Omega\) (encoded as 0x800000) will occur in the basis if it is in the subspace, and that there are many even vectors (i.e. vectors orthogonal to \(\Omega\)) in the basis.
- int32_t leech2_matrix_orthogonal(uint64_t *a, uint64_t *b, uint32_t k)
Compute standard orthogonal complement in Leech lattice mod 2.
Let \(A = a_0\ldots, a_{k-1}\) be a matrix of \(k\) vectors in the Leech lattice mod 2 stored in the array
a
. The function returns a basis \(B = b_0\ldots, b_{23}\) of the Leech lattice mod 2 in the arrayb
, and it returns a number \(m\) such that the vectors \(b_m\ldots, b_{23}\) are a basis of the orthogonal complement of the space generated by the row vectors of \(A\).If the vectors \((a_0\ldots, a_{k-1})\) are linear independent then the function returns \(m = k\), and vector \(b_i, i < k\) is orthogonal to all vectors \(a_j\) with \(j \neq i\).
The basis \(B = b_0\ldots, b_{23}\) is stored in the array
b
.We require \(k \leq 24\). The function returns \(m \geq 0\) in case of success a negative value in case of failure.
- uint32_t leech2_matrix_radical(uint32_t *v2, uint32_t n, uint64_t *basis, uint32_t d)
Radical of subspace generated by vectors of Leech lattice mod 2.
Compute the radical of the subspace of the Leech lattice modulo 2 generated by the vectors
v2[0],...,v2[n-1]
. Here the radical is the intersection of the space generated byv2[0],...,v2[n-1]
with the orthogonal complement of that space.Input parameters
v2, n,
andd
are as in functionleech2_matrix_basis
. A basis of the radical of the space is computed inbasis
. The basis is echelonized as in functionleech2_matrix_basis
. The function returns the dimensionk
of radical spanned by that basis.
- uint32_t leech2_matrix_expand(uint64_t *basis, uint32_t dim, uint32_t *v2)
List vectors in a subspace of the Leech lattice modulo 2.
The function computes all
2**dim
vectors of the subspaceV
of the Leech lattice modulo 2 given by the basis
basis[0], ..., basis[dim - 1]
.These vectors are written into the array
v2
. The function
- void leech3_vect_mod3_to_signs(uint64_t *v, uint64_t mult, uint32_t n, uint64_t *signs)
Map vector in rep of the Monster mod 3 to array of signs.
Let
v
be a part of a vector of the 198884-dimensional representation of the monster group modulo 3, which is organized as an
times24
matrix of integers mod 3. Herev
is the relevant part of a vector encoded as in themmgroup.mm_op
extension; see The C interface of the mmgroup project, section Description of the mmgroup.mm extension for details.Let
mult
be a vector of 24 integers mod 3 encoded in the Leech lattice mod 3 encoding.The function computes the scalar product of each row of
v
withmult
and stores then
signs of these products in the arraysign
. Here the signs are stored in natural order and encoded as in functionqstate12_to_signs
in moduleqstate12io.c
. As usual, the integers 0, 1, and 2 (mod 3) are mapped to 0, ‘+’, and ‘-’, respectively.Output array
signs
should have at least(n + 31) >> 5
entries.
C functions in involutions.c
File
involutions.c
contains functions for transforming involutions of the subgroup \(G_{x0}\) (of structure \(2^{1+24}.\mbox{Co}_1\)) of the monster.We try to transform such involutions to a standard form via conjugation by elements of the monster group.
Functions
- int32_t xsp2co1_involution_invariants(uint64_t *elem, uint64_t *invar)
Compute invariant spaces for an involution in \(G_{x0}\).
Let \(g\) be the element of the group \(G_{x0}\) stored in the array given by parameter
elem
. Let \(\Lambda_2\) be the Leech lattice mod 2, with vectors in \(\Lambda_2\) coded in Leech lattice encoding as usual. Conjugation by \(g\) is a linear operation on \(\Lambda_2\), since the vectors in \(\Lambda_2\) correspond to the elements of the normal subgroup \(Q_{x0}\) of structure \(2^{1+24}\) (modulo the centre of \(G_{x0}\)). Let \(A = A(g)\) be the \(24 \times 24\) bit matrix that performs this operation on \(\Lambda_2\) by right multiplication. Put \(A_1 = A - 1\), and let \(I_1\) be the image of matrix \(A_1\).In this function we require that the image of \(g\) in the factor group \(\mbox{Co}_1\) of \(G_{x0}\) has order 1 or 2; othereise the function fails. That condition is equivalent to \(A^2 = 1\), and also to \(A_1^2 = 0\). If this is the case then we have:
\((\ker A_1)^\perp = I_1 \subset \ker A_1 = (I_1)^\perp\).
Any element \(v \in \ker A_1\) is invariant under \(g\), and so the corresponding element in \(Q_{x0}\) is invariant up to sign. The elements of \(Q_{x0}\) invariant under \(g\) (modulo the center of \(Q_{x0}\)) form a subspace \((\ker A_1)^+\) of \(\ker A_1\) of codimension \(0\) or \(1\). Let \((I_1)^+\) be the orthogonal complement of \((\ker A_1)^+\). Then \(I_1\) has the same codimension in \((I_1)^+\). The purpose of this function is to compute a basis of the smaller of the two spaces \((I_1)^+\) or \(\ker A_1\).
We compute an output matrix in the array
invar
and return the numberk
of rows of that matrix in case of success. We use the following column bits of the output matrix.23,…,0: Basis vector \(v_i\) of \(I_1\) or \((I_1)^+\)
55,…,32: Preimage (under \(A_1\)) of basis vector \(v_i\), undefined if \(v_i \notin I_1\)
27: Here a nonzero bit in row 0 indicates an error.
In bits 24,…,26 of the output matrix we return the following linear forms on the space spanned by basis vectors:
Case 1: \(I_1 = (I_1)^+\) or \(I_1 = \ker A_1 \)
Then we return a basis of \(I_1\), and we have \(k = \dim I_1 = \dim (I_1)^+ \in \{0, 8, 12\}\)
Bit 26: 0
Bit 25: type of basis vector (modulo 2)
Bit 24: sign of basis vector in \(I_1\)
Case 2: \(I_1 \neq (I_1)^+\) and \(I_1 \neq \ker A_1 \)
Then we return a basis of \((I_1)^+\), and we have \(k - 1 = \dim (I_1)^+ - 1 = \dim I_1 \in \{0, 8\}\).
Bit 26: 0 if and only if the basis vector is in \(I_1\)
Bit 25: 0
Bit 24: sign of the basis vector if the vector is in \(I_1\), and type of the basis vector (mod 2) otherwise
Parameter
invar
must be an array of length 12. Zero lines are appeded to that array so that its length will be 12.The function returns the dimension
k
of the computed basis, and a negative value in case of error. The return value ERR_QSTATE12_GX0_BAD_ELEM means that that the image of \(g\) in \(\mbox{Co}_1\) has order greater than \(2\).Bits 26,…,0 of the output matrix are echelonized in a special way. Here the columns are processed in the order:
26, 25, 24, 11, 22, 21, …, 13, 12, 10, 9, …, 1, 0, 23.
One of the advantages of this echelonization is that the vector \(\Omega\) (encoded as 0x800000) will occur in the basis if it is in the subspace, and that there are many even vectors (i.e. vectors orthogonal to \(\Omega\)) in the basis. Also, bits 26, 25, 24 may be nonzero at most in the first two columns of the output matrix.
- int32_t xsp2co1_involution_orthogonal(uint64_t *invar, uint32_t col)
Compute some orthogonal complement for involution invariants.
Let \(g\) be an element of the group \(G_{x0}\) such that the image of \(g\) in \(\mbox{Co}_1\) has order 1 or 2. For that element \(g\), let \(A, A_1\), and \(I_1\) be as in function
xsp2co1_involution_invariants
.In this function the input parameter
invar
must be equal to the outputinvar
of functionxsp2co1_involution_invariants
applied to the element \(g\).There is a nondegenerate bilinear form \( \langle \langle .,. \rangle \rangle\) on \(I_1\) given by
\(\langle \langle x,y \rangle \rangle = \langle \pi(x),y \rangle\),
where \(\pi(x)\) is any preimage of \(x\) under \(A_1\), and \(\langle .,. \rangle\) is the scalar product on the Leech lattice modulo 2. The form \(\langle \langle .,. \rangle \rangle \) is also called the Wall parametrization, see [Wal63]. If the image of \(g\) in \(\mbox{Co}_1\) has order at most two then the Wall parametrization is a symmetric bilinear form.
The function computes the orthogonal complement \(v\) of a linear form \(l\) on the Leech lattice modulo 2 under the Wall parametrization. Then \(v\) is a vector in the Leech lattice modulo two. If parameter
col
is 0 or 1 then we let \(l\) be the linear form in columncol + 25
of matrixinvar
.The function returns \(v\) in case of success and a negative value in case of failure.
[Wal63] G. E. Wall. On the conjugacy classes in the unitary, symplectic and orthogonal groups. J. Australian Math. Soc. 3, pp 1–63, 1963.
- int32_t xsp2co1_involution_find_type4(uint64_t *invar, uint32_t guide)
Find type-4 vector in a space computed by
xsp2co1_involution_invariants
.Let \(g\) be the element of the group \(G_{x0}\), and for that element \(g\) let \(A, A_1, I_1\), and \((I_1)^+\) be as in function
xsp2co1_involution_invariants
.Here input parameter
invar
must be the outputinvar
of functionxsp2co1_involution_invariants
applied to the element \(g\). This function is successful in case \(\dim I_1 = 8\) only.We return a type-4 vector the space \(I_1\). If no such vector exists then we return 0.
Parameter
guide
should usually be zero. Ifguide
is a type-4 vector in the Leech lattice mod 2 satisfying the assumptions the return valuev
then the function returnsv = guide
. Otherwise parameterguide
is ignored.
- int32_t xsp2co1_elem_find_type4(uint64_t *elem, uint32_t guide)
Try to simplify an element in \(G_{x0}\) via conjugation.
Let \(g\) be the element of the group \(G_{x0}\) stored in the array given by parameter
elem
. In this function we require that the image of \(g\) in the factor group \(\mbox{Co}_1\) of \(G_{x0}\) has order 1 or 2; otherwise the function fails.Let \(\Lambda_2\) be the Leech lattice mod 2, with vectors in \(\Lambda_2\) coded in Leech lattice encoding as usual. Let \(\Omega\) be the standard frame in \(\Lambda_2\).
Then the function tries to find a vector \(v \in \Lambda_2\) with the following property:
For any \(h \in G_{x0}\) with \(v \cdot h = \Omega\) we have \(h^{-1} g h \in N_{x0}\).
The function returns \(v\) in case of success and a negative value in case of an error. It returns
ERR_QSTATE12_GX0_BAD_ELEM
if no suitable vector \(v\) has been found.The function succeeds if the following two conditions hold:
\(g\) is in class 1A, 2A, 2B or 4A of the monster group
\(g^2\) is in subgroup \(Q_{x0}\) of \(G_{x0}\).
In these two cases there is also a power \(\tau^e\) of the triality element \(\tau\) with
\(\tau^{-e} h^{-1} g h \tau^e \in Q_{x0}\).
Caution:
The last statement has been checked for classes 1A, 2A and 2B only!
Parameter
guide
should usually be zero. Ifguide
is a type-4 vector in the Leech lattice mod 2 satisfying the assumptions the return valuev
then the function returnsv = guide
. Otherwise parameterguide
is ignored. It is also ignored in case \(g \in Q_{x0}\).
- int32_t xsp2co1_elem_conj_G_x0_to_Q_x0(uint64_t *elem, uint32_t *a)
Try to map an element of \(G_{x0}\) to \(Q_{x0}\).
Let \(g\) be the element of the group \(G_{x0}\) stored in the array given by parameter
elem
. The function tries to find an element \(h\) in the monster group with \(h^{-1} g h = q \in Q_{x0}\).The function succeeds if the following two conditions hold:
\(g\) is in class 1A, 2A, 2B or 4A of the monster group
\(g^2\) is in subgroup \(Q_{x0}\) of \(G_{x0}\).
The function stores \(h\) in the output array
a
as a word of generators of the monster group. Arraya
must be of length 7 . The function returns \(q\) in bits24,...,0
of the return value, and number of atoms in the arraya
in bits27, 26, 25
of the return value The data in the arraya
are padded with zeros.The function returns a negative value in case of failure. It returns
ERR_QSTATE12_GX0_BAD_ELEM
if no suitable element \(h\) can be found.
- int32_t xsp2co1_elem_conjugate_involution(uint64_t *elem, uint32_t *a)
Map an involution in \(G_{x0}\) to a standard form.
Let \(g\) be an involution of the group \(G_{x0}\) stored in the array given by parameter
elem
.The function computes an element \(a\) in the monster such that \(h = a^{-1} g a\) is one of the following elements of the subgroup \(Q_{x0}\) of \(G_{x0}\):
If \(g = 1\) then \(h = a = 1\).
If \(g\) is a 2A involution then \(h\) is the involution in \(Q_{x0}\) corresponding to the Golay cocode word with entries \(2,3\) being set.
If \(g\) is a 2B involution then \(h\) is the central involution \(z\) in \(Q_{x0}\).
The element \(a\) is stored in the array
a
as a word of generators of the monster group. In case of success the function returns0x100 * I + len(a)
, wherelen(a)
is the length of the arraya
. We putI = 0
if \(g = 1\). We putI = 1, 2
if \(g\) is a 2A or 2B involution, respectively.The function returns
ERR_QSTATE12_GX0_BAD_ELEM
if \(g\) is not an involution.The array
a
must have length at least \(14\).
C functions in xsp2co1_traces.c
File
xsp2co1_traces.c
contains functions for computing characters of some representations of the subgroup \(G_{x0}\) (of structure \(2^{1+24}.\mbox{Co}_1\)) of the monster.Such computations can be very expensive, especially for some classes of involutions, or for elements that map to involutions in the factor group \(\mbox{Co}_1\) of \(G_{x0}\).
This file contains a function
xsp2co1_elem_involution_class
for the classification of elements that map to involutions in \(\mbox{Co}_1\).Function
xsp2co1_traces_fast
uses a precomputed table for computing the characters of elements of \(G_{x0}\). That table is addressed by the class information computed by functionxsp2co1_elem_involution_class
. The functions in modulemmgroup\tests\test_involutions.make_involution_samples.py
precompute that table. We simply copy and paste the table from the output of that python function to to this file.The precomputation of the table requires the function
xsp2co1_traces_all
in filexsp2co1_elem.c
. That function computes the same characters as functionxsp2co1_traces_fast
without using precomputed tables.Function
xsp2co1_elem_involution_class
does not use a precomputed table, but the verification of this function requires inspection of the output of the modulemake_involution_samples.py
mentioned above.Functions
- int32_t xsp2co1_elem_involution_class(uint64_t *elem)
Compute class information for certain elements of \(G_{x0}\)
Let \(g \in G_{x0}\) be stored in the array
elem
in G_x0 representation. If \(g\) maps to an involution in the factor group \(\mbox{Co}_1\) of \(G_{x0}\) then the function returns a nonzero value indicating some class information about \(g\). Otherwise the function returns 0.The class information in the return value is to interpreted as follows:
bits 7 .. 0: class of element g in the Monster group, e.g 0x21 means class 2A, 0x41 means class 4A, 0x42 means class 4B, etc. bits 11 .. 8: Class of element g in the factor group Co_1 0 means class 1A in Co_1 1 means class 2A in Co_1 2 means class 2B in Co_1 3 means class 2C in Co_1 bit 12: 0 if g and -g are in the same class in the Monster 1 otherwise bit 13: 1 if q g is equal to or powers up to -1 0 otherwiseAll other bits in the return value are set to zero.
Here \(-1\) is the central involution \(x_{-1}\) in \(G_{x0}\), and \(-g = x_{-1} \cdot g\) .
Write \(h(g)\) as an abbreviation for the result of this function applied to an element \(g\) of \(G_{x0}\). Then the following assertions have been checked computationally in files
make_involution_samples.py
, ortest_xp2_traces.py
, or can easily be checked mathematically.Possible values \(h(g)\) (depending on the class of \(g Q_{x0}\)) in \(\mbox{Co}_1\) are:
class 1A: 0x1011, 0x3022, 0x0022, 0x0021, 0x2041 class 2A: 0x1121, 0x1122, 0x0143, 0x2143, 0x0142, 0x0141, 0x0122 class 2B: 0x0244, 0x2244 class 2C: 0x0322, 0x0341, 0x0344, 0x2382, 0x0343, 0x0342The value \(h(g)\) determines the characters of the representations \(98280_x, 299_x, 24_x, 4096_x\) of \(g\) uniquely, where by construction of \(G_{x0}\) the last two characters are determined up to sign only.
The class of an involution \(g\) is determined uniquely by \(h(g)\).
- int32_t xsp2co1_traces_fast(uint64_t *elem, int32_t *ptrace)
Compute relevant characters of element of \(G_{x0}\).
Let \(g \in G_{x0}\) be stored in the array
elem
in G_x0 representation. The function computes the characters of the representations \(\rho_{24}, \rho_{576}, \rho_{4096}, \rho_{98280}\) and stores the result inptrace[0],..., ptrace[3]
in that order. Here \(\rho_{576}\) is the tensor square of \(\rho_{24}\).This function returns 0 in case of success and a nonzero value otherwise.
Note that the tensor product \(\rho_{24} \otimes \rho_{4096}\) is well defined, but the factors of that product are defined up to sign only. We normalize the characters corresponding to \(\rho_{24}\) and \(\rho_{4096}\) so that the first nonzero value of these two characters (in the order given above) is positive.
So this function performs the same action as function
xsp2co1_traces_all
in filexsp2co1_elem.c
, but it is considerably faster, since it uses precomputed tables for som hard cases.
- int32_t xsp2co1_elem_conjugate_involution_Gx0(uint64_t *elem, uint32_t guide, uint32_t *a)
Map an involution in \(G_{x0}\) to a standard form.
Let \(g\) be an involution in the group \(G_{x0}\) stored in the array given by parameter
elem
in G_x0 representation.The function computes an element \(a\) in \(G_{x0}\) such that \(h = a^{-1} g a\) is a (fixed) representative of the class of \(g\) in the group \(G_{x0}\).
The element \(a\) is stored in the array
a
as a word of generators of the monster group. In case of success the function returns0x100 * iclass + len(a)
, wherelen(a)
is the length of the data in the arraya
, andiclass
is explained below. The function returns a negative value in case of failure, e.g. if \(g\) has order greater than 2. The arraya
must have length at least \(10\).In the sequel we list the representatives of all classes of involutions in \(G_{x0}\) computed by this function. For any such representative we also list the number
iclass
indicating the class of the involution as computed by functionxsp2co1_elem_involution_class
.
iclass = 0x1101
: the neutral element \(x_1\)
iclass = 0x3022
: the central involution \(x_{-1}\)
iclass = 0x0021
: the element \(x_{\{2,3\}}\)
iclass = 0x0022
: the element \(x_{\Omega}\)
iclass = 0x1121
: the element \(y_o\)
iclass = 0x1122
: the element \(x_{-1} y_o\)
iclass = 0x0122
: the element \(y_o x_{\{8,9\}}\)
iclass = 0x0322
: the element \(y_D x_{\{0, 12\}}\)Here in \(x_{\{i,j\}}\) the index \(\{i,j\}\) indicates a Golay cocode word of length 2 given by the entries \(i\) and \(j\). Octad \(o\) is the standard octad \(\{0,1,2,3,4,5,6,7\}\). Dodecad \(D\) is the standard dodecad \(\{0, 4, 8, 13, 14, 15, 17, 18, 19, 21, 22, 23\}\).
Parameter
guide
should usually be zero. Ifguide
is a type-4 vector \(v_4\) in the Leech lattice mod 2 such that the two conditions \(h = a^{-1} g a\) and \(v_4 \cdot a = \Omega\) can both be achieved then we compute an element \(a\) satisfying these two conditions. Otherwise parameterguide
is ignored. Here \(\Omega\) is the standard frame in the Leech lattice.
- int32_t xsp2co1_map_involution_class_Gx0(uint32_t iclass, uint32_t *a)
Map an involution class in \(G_{x0}\) to its representative.
Here parameter
class
must be a class number of an involution in the group \(G_{x0}\) as returned by functionxsp2co1_elem_conjugate_involution_Gx0
.Then the function computes the representative \(h\) of the class of involutions in \(G_{x0}\) as it is computed by function
xsp2co1_elem_conjugate_involution_Gx0
.The element \(h\) is stored in the array
a
as a word of generators of the monster group. In case of success the function returns the lengthlen(a)
of the data in the arraya
. The function returns a negative value in case of failure, e.g. ificlass
does not correspond to an involution. The arraya
must have length at least \(2\).
C functions in xsp2co1_map.c
File
xsp2co1_map.c
contains functions for computing an element \(g\) of the group \(G_{x0} = 2^{1+24}.\mbox{Co}_1\) from the action of \(g\) on the normal subgroup \(Q_{x0} = 2^{1+24}\) of \(G_{x0}\).Here the group \(G_{x0}\) is the maximal subgroup of the Monster used in our construction of the Monster. We store an element of \(G_{x0}\) as word of generators of that group as described in file
mmgroup_generators.h
. Internally, we also use the G_x0 representation for elements of \(G_{x0}\) as described in filexsp2co1.c
.Elements of the group \(Q_{x0}\) are stored in Leech lattice encoding as described in section Description of the mmgroup.generators extension.
Note that an element of \(G_{x0}\) is determined by its action on \(Q_{x0}\) up to sign only.
The main function
xsp2co1_elem_from_mapping
in this module tries to find the ‘nicer’ of the elements \(\pm g\) from its action on \(Q_{x0}\).Functions
- int32_t xsp2co1_Co1_get_mapping(uint32_t *m1, uint32_t *m2, uint32_t *m_out)
Compute a certain mapping from \(Q_{x0}\) to itself.
Let \(g \in G_{x0}\) be such that \(g\) maps \(m_{1,j}\) to \(m_{2,j}\) via conjugation, for \(m_{i,j} \in Q_{x0}\), \(i = 1,2; 0 \leq j \leq 24\). If the \(m_{1,j}\) (considered as vectors in \(\Lambda/2 \Lambda\)) are linear independent then there is at most one such \(g\), up to sign.
Here inputs \(m_{1,j}, m_{2,j}\) are given in the arrays
m1, m2
in Leech lattice encoding.The function computes \(g\) as a mapping \(m_{0,j} \mapsto m_{3,j}\), where \(m_{0,j}\) is the standard basis of \(\Lambda/2 \Lambda\) (with \(m_{0,j}\) =
1 << j
in Leech lattice encoding). The function stores the vectors \(m_{3,j}\) in the arraym_out
of length 24 in Leech lattice encoding.Let \(o\) be the odd part of the order of \(g\), so that \(g\) has order \(2^k \cdot o\).
The function returns a negative value if it detects an error, and it returns \(o\) if it does not detect any error. If the function returns \(o \geq 0\) and the output is a correct image of the standard basis then there exists a \(g \in G_{x0}\) that maps \(m_{1,j}\) to \(m_{2,j}\). The order of any such element \(g\) divided by \(o\) is a power of two.
Any overlapping between the arrays referred by
m1, m2, m_out
is allowed.
- int32_t xsp2co1_Co1_matrix_to_word(uint32_t *m, uint32_t *g)
Compute preimage in \(G_{x0}\) of automorphism on \(Q_{x0}\).
Let matrix \(m\) (given by parameter
m
) be a 24 times 25 bit matrix that describes an automorphism \(g'\) acting on \(Q_{x0}\). Here rowm[i]
is the image of the (positive) element in \(Q_{x0}\) corresponding to thei
-th basis vector of \(\Lambda/2\Lambda\), andm[i]
is encoded in Leech lattice encoding.If possible, the function computes a \(g \in G_{x0}\) that acts on \(Q_{x0}\) by conjugation in the same way as \(g'\) acts on \(Q_{x0}\). If such a \(g\) exists, it is determined up to sign only.
In case of success the function stores \(g\) as a word of generators of \(G_{x0}\) in the buffer referred by parameter
g
and returns the length of that word. In case of failure the function returns a negative value.Array
g
must have length at least 10.
- int32_t xsp2co1_elem_from_mapping(uint32_t *m1, uint32_t *m2, uint32_t *g)
Compute \(g \in G_{x0}\) from its operation on \(Q_{x0}\).
Let \(g \in G_{x0}\) be such that \(g\) maps \(m_{1,j}\) to \(m_{2,j}\) via conjugation, for \(m_{i,j} \in Q_{x0}\), \(i = 1,2; 0 \leq j \leq 24\). If the \(m_{1,j}\) (considered as vectors in \(\Lambda/2 \Lambda\)) are linear independent then there is at most one such \(g\), up to sign.
Here inputs \(m_{1,j}, m_{2,j}\) are given in the arrays
m1, m2
in Leech lattice encoding.If possible then the function computes a \(g \in G_{x0}\) that maps \(m_{1,j}\) to \(m_{2,j}\) via conjugation. In case of success it stores \(g\) as a word of generators of \(G_{x0}\) in the buffer referred by parameter
g
and returns the length of that word in the lower 8 bits of the return value. In case of failure the function returns a negative value.Array
g
must have length at least 10.Note that \(g\) is determined up to sign only. The function makes a considerable effort to disambiguate the two elements \(\pm g\).
If one of the two element \(\pm g\) has odd order then the other one has necessarily even order; in that case we return the element with odd order. Otherwise both elements have the same (even) order \(2^k \cdot o, o\) odd. Then at most one of the elements \(\pm g^o\) may have a negative character \(\chi(g^o)\) in the representation \(\rho_{24} \otimes \rho_{4096}\) of \(G_{x0}\); and in this case we return an element with \(\chi(g^o) \geq 0\). This leads to a disambiguation of \(\pm g\) in case \(\chi(g^o) \neq 0\).
We store the order of the computed element \(g\) in bits 15…,8 of the return value. We set bit 16 of the return value precisely if we could disambiguate \(g\) from \(-g\), i.e. in case \(\chi(g^o) \neq 0\). (Note that \(g^o = 1\) if \(g\) has odd order, implying \(\chi(g^o) > 0\).)
The function returns a negative value in case of failure.
Description of the mmgroup.mm_op
extension
Module mmgroup.mm_op
is implemented as an extension
in the mmgroup
package implemented in Cython
.
The main source file for that extension is mm_op.pyx
in
directory src.mmgroup.dev.mm_op
. Each documented .c
in this module function has been wrapped by a Cython
function with the same name and the same signature.
Module mmgroup.mm_op
implements the 196884-dimensional rational
representation \(\rho_p\) of the monster group modulo several
fixed odd moduli \(p = 2^k-1\).
Representation of a vector in \(\rho_p\)
We describe the representations of a vector in \(\rho_p\)
The most important representation of a vector in \(\rho_p\) is the internal representation. All operations of the monster group are performed on vectors in in \(\rho_p\) in internal representation.
In the internal representation a vector is stored as an array of
247488
entries, where each entry is a bit field representing
an integer modulo p
. Some components of a vector are stored
twice in that array and some entries of the array are unused. This
special structure facilitates the implementation of the operations
of the monster group.
The entries of a vector are organized as tuples (tag, i0, i1)
.
Here indices i0, i1
refer to a two-dimensional array as
indicated in column Size
of the following table. As usual in
C, entries with adjacent last index i1
are stored in adjacent
locations. For a mathematical description of an entry
(tag, i0, i1)
, see section
The Representation of the Monster Group in the API reference.
Tag
Size
Space used
Remarks
Offset
A
24 x 24
24 x 32
(1), (2)
0
B
24 x 24
24 x 32
(1), (2), (3)
768
C
24 x 24
24 x 32
(1), (2), (3)
1536
T
759 x 64
759 x 64
(4),
2304
X
2048 x 24
2048 x 32
(1),
50880
Z
2048 x 24
2048 x 32
(1),
116416
Y
2048 x 24
2048 x 32
(1),
181952
Remarks
As indicated in column
Space used
, an array of sizen
times24
is stored in a space reserved for an array of sizen
times32
. So the entry with index(tag, i0, i1)
is stored at locationOffset(tag) + 32 * i0 + i1
. Unused entries must be equal to zero.The entry given by
(tag, i0, i1)
must be equal to the entry given by(tag, i1, i0)
.The diagonal entry given by
(tag, i0, i0)
must be equal to zero.The entry with index
(T, i0, i1)
is stored at locationOffset(T) + 64 * i0 + i1
.
The entries of a vector in internal representation are stored
a one-dimensional array of integers of type uint_mmv_t
. Here
type uint_mmv_t
may be one of the C integer types
uint64_t
or uint32_t
, depending on the value INT_BITS
.
At present INT_BITS
is set to the value 64. Several adjacent
entries of a vector are stored as bit fields in a single integer
of type uint_mmv_t
. Entries with a lower index are stored at
bits with lower valence.
The number of bits in a bit field is always a power of two. So e.g.
for p = 3
we use 2
bits; for p = 7
we use 4
bits
with the highest bit unused. In case p = 2**k - 1
, legal values
for an entry are 0,...,2**k - 1
, with 2**k - 1
equal to
0
. Thus negation of a value can be done by complementing all
k
bits of that value. Apart from negation, the matrices
corresponding to operations of the monster may add, subtract and
half the entries of a vector (modulo p
). These operations can
easily be done on several entries simultaneously by manipulating a
just single integer of type uint_mmv_t
.
As indicated above, we reserve 32
entries for arrays of
integers modulo p
with 24
entries. So we require about
25.7%
more memory than necessary. In some cases we need this
extra memory anyway. E.g. for p = 3
a 64
-bit integer may
store 32
entries, so that there will always be a slack of
8
entries when storing 24
entries.
Function mm_aux_mmv_size(p)
returns the number of integers
of type uint_mmv_t
required for storing a vector in external
representation.
When writing or calculating entries with tags A, B, C
then
the high-level function for manipulating vectors in internal
representation make sure that e.g. entries with indices
(A, i0, i1)
and (A, i1, i0)
are always set to the same
value. These functions also make sure that unused bits in a bit
field and unused bit fields are set to zero. Note that a bit field
with value zero may contain the value p
instead.
The external representation of a vector in \(\rho_p\)
There is also a so-called external representation of a vector in R_p. This is used to facilitate the access to vectors by external modules. Here the vector is represented as an array of 196884 integers of type uint8_t. Basis vectors are ordered similar to the ordering for the internal representation, but here the entries are in one-to-one correspondence with the basis vectors. In the external representation there are no unused or duplicated entries.
More precisely, the order of the entries is:
Entries
Condition
No of entries
Offset
(A, i0, i1)
i0 = i1
24
0
(A, i0, i1)
i0 > i1
276
24
(B, i0, i1)
i0 > i1
276
300
(C, i0, i1)
i0 > i1
276
576
(T, i0, i1)
759*64
852
(X, i0, i1)
2048*24
49428
(Z, i0, i1)
2048*24
98580
(Y, i0, i1)
2048*24
147732
Indices (tag, i,j
) for tag = A, B, C
, i > j
are ordered
as follows:
(1,0),
(2,0), (2,1),
(3,0), (3,1), (3,2),
...
(i,0), (i,1), ..., (i,i-1),
...
(24,0), (24,1), ..., (24,23).
Function mm_aux_bytes_to_mmv()
converts a vector from external
to internal representation, Function mm_aux_mmv_to_bytes()
does
the inverse conversion.
The sparse representation of a vector in \(\rho_p\)
The Python interface to vectors in \(\rho_p\) is optimized for readability and not for speed. Here a typical task is to read and modify single entries of a vector. In the internal representation the coordinates of a vector are indexed by tuples containing a string. Transferring tuples or strings from Python to C is awful. Here we need a representation of a vector in \(\rho_p\) where a single entry of a vector can be stored in an integer variable.
A vector in \(\rho_p\) can be stored in the sparse
representation.
Here a vector is stored as an array of 32-bit integers, where each
entry stands for a multiple of a basis vector. A component of
a vector is stored in the bit fields of an integer as a tuple
(tag, i0, i1, value)
. Here the tuple (tag, i0, i1)
is as
in the external representation, and value
is the value of the
coordinate of the vector corresponding to (tag, i0, i1)
.
Entries with coordinate zero may be dropped. A 32-bit integer
encodes a tuple (tag, i0, i1, value)
in bit fields as shown
in the following table.
Bits
Meaning
27..25
Tag
:A = 1
,B = 2
,C = 3
,T = 4
,X = 5
,Z = 6
,Y = 7
24..15
Index
i0
13.. 8
Index
i1
7.. 0
The
value
of the coordinate of the basis vector; if the modulusp
is2**k - 1
then only the lowestk
bits are evaluated.
In a C function the length of a sparse representation of a vector
must be given as a parameter to the function.
The order of the entries is irrelevant in the sparse
representation. A sparse representation generated by a C function
contains at most one entry for each tuple (tag, i0, i1)
.
On input, entries with several equal tuples (tag, i0, i1)
are
accepted. Unless stated otherwise, the corresponding values of
such equal tuples are added.
In an entry with tag A
, B
, or C
generated by this module
we always have i0 >= i1
. The value
of an entry generated by
this module is always less than the modulus p
.
When reading an entry, a value
with 0 <= value <= p
is
accepted. Entries with tag A
, B
, or C
and i < j
are
also accepted. Illegal tags or indices are usually ignored on input.
Header file mm_basics.h
The header file mm_basics.h
contains basic definitions for dealing with vectors of the 198884-dimensional representation of the monster group, as described in The C interface of the mmgroup project, section Description of the mmgroup.mm extension.
It also contains prototypes for the C files in the mm
extension. This extension comprises the files mm_aux.c
, mm_crt.c
, mm_group_word.c
, mm_random.c
, mm_tables.c
, mm_tables_xi.c
.
Defines
-
mm_aux_bad_p(p)
Return 0 if
p
is a good modulus and a nonzero value otherwise.
Typedefs
-
typedef uint64_t uint_mmv_t
Used for the representation of the monster group.
Internally, a vector in the 196884-dimensional representation of the monster is stored as an array of integers of type
uint_mmv_t
. Here several entries are stored in such an integer. Seeenum MM_AUX_OFS_type
for more details.
Enums
-
enum MM_AUX_OFS
This enumeration contains the offsets for the tags
A,B,C,T,X,Z,Y
in a vector in the 196884-dimensional representation of the monster, stored in the internal representation.Such an offset counts the number of entries starting at the beginning of th vector. Note that several entries of a vector are stored in a 64-bit integer. Also there may be duplicate or unused entries in a vector, in order to speed up the operation of the monster group on a vector.
Values:
-
enumerator MM_AUX_OFS_A
Offset for tag A
-
enumerator MM_AUX_OFS_B
Offset for tag B
-
enumerator MM_AUX_OFS_C
Offset for tag C
-
enumerator MM_AUX_OFS_T
Offset for tag T
-
enumerator MM_AUX_OFS_X
Offset for tag X
-
enumerator MM_AUX_OFS_Z
Offset for tag Z
-
enumerator MM_AUX_OFS_Y
Offset for tag Y
-
enumerator MM_AUX_LEN_V
Total length of the internal representation
-
enumerator MM_AUX_OFS_A
-
enum MM_AUX_XOFS
This enumeration contains the offsets for the tags
A,B,C,T,X,Z,Y
in a vector in the 196884-dimensional representation of the monster, stored in the external representation.In external representation, a vector is stored as a contiguous array of bytes.
Values:
-
enumerator MM_AUX_XOFS_D
Offset for diagonal entries of tag A
-
enumerator MM_AUX_XOFS_A
Offset for tag A
-
enumerator MM_AUX_XOFS_B
Offset for tag B
-
enumerator MM_AUX_XOFS_C
Offset for tag C
-
enumerator MM_AUX_XOFS_T
Offset for tag T
-
enumerator MM_AUX_XOFS_X
Offset for tag X
-
enumerator MM_AUX_XOFS_Z
Offset for tag Z
-
enumerator MM_AUX_XOFS_Y
Offset for tag Y
-
enumerator MM_AUX_XLEN_V
Total length of the external representation
-
enumerator MM_AUX_XOFS_D
-
enum MM_SPACE_TAG
This enumeration defines the values of the tags
A,B,C,T,X,Z,Y
in a vector in the 196884-dimensional representation of the monster, stored in the sparse representation.In the sparse representation an entry of a vector is stored as a tuple of bit fields
(tag, par1, par2, value)
inside an integer of typeuint32_t
as follows:Bits 27,...,25: tag (as indicated below) Bits 24,...,14: par1 (an integer of up to 11 bits) Bits 13,..., 8: par2 (an integer of up to 6 bits) Bits 7,..., 0: value (Reserved for the value of an entry)
Values:
-
enumerator MM_SPACE_TAG_A
Encodes tag A
-
enumerator MM_SPACE_TAG_B
Encodes tag B
-
enumerator MM_SPACE_TAG_C
Encodes tag C
-
enumerator MM_SPACE_TAG_T
Encodes tag T
-
enumerator MM_SPACE_TAG_X
Encodes tag X
-
enumerator MM_SPACE_TAG_Z
Encodes tag Z
-
enumerator MM_SPACE_TAG_Y
Encodes tag Y
-
enumerator MM_SPACE_TAG_A
-
struct mm_sub_op_pi64_type
- #include “mm_basics.h”
Auxiliary structure for the structure
mm_sub_op_pi_type
An array of type
mm_sub_op_pi64_type[759]
encodes the operation of \(x_\epsilon x_\pi\) on the representation of the monster group for entries with tagT
. Assume that entry(T, i, j)
is mapped to entry+-(T, i1, j1)
. Theni1
depends oni
only, andj1
depends oni
andj
. For fixedi
the mappingj -> j1
is linear if we consider the binary numbersj
andj1
as bit vectors.Entry
i1
of the array of typemm_sub_op_pi64_type[759]
describes the preimage of(T, i1, j1)
for all0 <= j1 < 64
as documented in the description of the memberspreimage
andperm
.Note that the values 1, 3, 7, 15, 31, 63 occur as differences
j1 ^ (j1 - 1)
when countingj1
from 0 up to 63. So the preimage of(T, i1, j1)
can be computed from the preimage of(T, i1, j1 - 1)
using linearity and the approprate entry in member perm.We remark that in case of an odd value epsilon the mapping for tag
T
requires a postprocessing step that cannot be derived from the infomration in this structure. Then entry(T, i, j)
has to be negated if the bit weight of the subset of octadei
corresponding to indexj
has bit weight 2 modulo 4.In the sequel we describe the meaning of entry
i1
an an array of elements of typemm_sub_op_pi64_type
.
-
struct mm_sub_op_pi_type
- #include “mm_basics.h”
Structure used for preparing an operation \(x_\epsilon x_\pi\).
Function
mm_sub_prep_pi
computes some tables required for the operation of \(x_\epsilon x_\pi\) on the representation of the monster group, and stores these tables in a structure of typemm_sub_op_pi_type
.The structure of type
mm_sub_op_pi_type
has the following members:Public Members
-
uint32_t eps
A 12-bit integer describing an element \(\epsilon\) of the Golay cocode.
-
uint32_t pi
An integer describing the element \(\pi\) of the Mathieu group \(M_{24}\) as in module
mat24_functions.c
.
-
uint8_t perm[24]
The permutation
0...23 -> 0...23
given by the element \(\pi\) of \(M_{24}\).
-
uint8_t inv_perm[24]
The inverse of the permutation
perm
.
-
uint32_t benes_net[9]
A representation of Benes network for computing permutationperm, as described in function
mat24_perm_to_net
in filemat24_functions.c
.
-
uint16_t tbl_perm24_big[2048 + 72]
For tags
A, B, C, X, Y, Z
, an entry(tag, i, j)
of the representation of the monster is mapped to entry(tag1, i1, j1)
, withi1
depending oni
(and the tag), andj1
depending onj
only.If
tbl_perm24_big[i1] & 0x7ff = i
for0 <= i1 < 2048
then(tag, i, j)
ia mapped to(Tag, i1, perm[j])
, up to sign, for tagsX
,Y
andZ
. In case of an odd \(\epsilon\), tagsY
andZ
have to be exchanged. The valuetbl_perm24_big[2048 + 24*k + i1] & 0x7ff
describes the preimage of(tag, i1, j1)
in a similar way, wheretag = A, B, C
, fork = 0, 1, 2
.Bits 12,…,15 of
tbl_perm24_big[i1]
encode the signs of the preimages of the corresponding entry of the rep. Bits 12, 13, and 14 refer to the signs for the preimages for the tagsX
,Z
andY
, respectively. Bit 15 refers to the signs for the preimages for tagsA
,B
andC
. If the corresponding bit is set, the preimage has to be negated.Note that function
mat24_op_all_autpl
in modulemat24_functions.c computes
the first 2048 entries of the table.
-
mm_sub_op_pi64_type *tbl_perm64
A description of the operation of \(x_\epsilon x_\pi\) on the entries with tag
T
, see structuremm_sub_op_pi64_type
. Entryd
of the Arrary refers to the octado(d)
with numberd
. It contains the followint information_Bits 5,…,0: Associator
\delta' = A(o(d), f))
encoded as a suboctadBits 11,…,6: Associator
a = A(o(d), ef))
encoded as a suboctad.Caution:
Pointer
tbl_perm64
must be initialized with an array of typemm_sub_op_pi64_type a_tbl_perm64[759]
.
-
uint32_t eps
-
struct mm_sub_op_xy_type
- #include “mm_basics.h”
Structure used for preparing an operation \(y_f x_e x_\epsilon\).
The operation of \(g = y_f x_e x_\epsilon\), (or, more precisely, of its inverse \(g^{-1}\)) on the representation of the monster group is described in section Implementing generators of the Monster group in the The mmgroup guide for developers.
Function
mm_sub_prep_xy
in filemm_tables.c
collects the data required for this operation in a structure of typemm_sub_op_xy_type
.Public Members
-
uint32_t f
A 13-bit integer describing an element \(f\) of the Parker loop.
-
uint32_t e
A 13-bit integer describing an element \(e\) of the Parker loop.
-
uint32_t eps
A 12-bit integer describing an element \(\epsilon\) of the Golay cocode.
-
uint32_t f_i
Bit \(i\) of member
f_i
is the scalar product of \(f\) and the singleton cocode word \((i)\).These bits are used for the operation of \(g^{-1}\) on entries with tag
A
.
-
uint32_t ef_i
Bit \(i\) of member
ef_i
is the scalar product of \(ef\) and the singleton cocode word \((i)\).These bits are used for the operation of \(g^{-1}\) on entries with tags
B
, andC
.
-
uint32_t lin_i[3]
Put \(g_0 = e\), \(g_1 = g_2 = f\). For
k = 0, 1,2
, the bit \(i\) of memberlin_i[k]
is the scalar product of \(g_k\) and the singleton cocode word \((i)\).These bits are used for the operation of \(g^{-1}\) on entries with tags
X
,Z
, andY
.
-
uint32_t lin_d[3]
Let
U_k = X, Z, Y
fork = 0, 1, 2
. If the cocode element \(\epsilon\) is even then we putU'_k = U_k
, otherwise we putU'_k = X, Y, Z
fork = 0, 1, 2
. The operation \(g^{-1}\) maps the vector with tag(U_k, d, i)
to(-1)**s
times the vector with tag(U'_k, d ^ lin[d], i)
. Here**
denotes exponentiation and we haves
=s(k, d, i)
=(lin_i[k] >> i) + (sign_XYZ[d] >> k)
.If
k = 0
and \(\epsilon\) is odd then we have to corrects(k, d, i)
by a term<d, i>
.
-
uint8_t *sign_XYZ
Pointer
sign_XYZ
refers to an array of length 2048. This is used for calculations of signs as described above. Here we use the formula in section Implementing generators of the Monster group of the mmgroup guide for developers, dropping all terms depending oni
.
-
uint16_t *s_T
Pointer
s_T
refers to an array of length 759. Entryd
of this array refers to the octado(d)
with numberd
. The bits of entryd
are interpreted as follows:Bits 5,…,0: The asscociator
delta' = A(o(d), f)
encoded as a suboctad of octado(d))
.Bits 13,…,8: The asscociator
alpha = A(o(d), ef)
encoded as a suboctad of octado(d))
. From his information we can compute the scalar product<ef, \delta>
for each suboctaddelta
ofo(d)
as an intersection of tow suboctads. Here we assume thatdelta
is represented as such a suboctad.Bit 14: The sign bit
s(d) = P(d) + P(de) + <d, eps>
, whereP(.)
is the squaring map in the Parker loop.Bit 15: Parity bit
|eps|
of the cocode wordeps
.Then \(g^{-1}\) maps the vector with tag
(T, d, delta)
to(-1)**s'
times the vector with tag(T, d, \delta ^ delta')
. Here**
denotes exponentiation and we haves'
=s'(T, d, delta)
=s(d)
+<\alpha, \delta>
+|delta| * |eps| / 2
.Here the product
<\alpha, \delta>
must be computed as the bit length of an intersection of two suboctads.
-
uint32_t f
Header file mm_op_p.h
C interface for file mm_index.c
File mm_index.c
provides the basic functions for converting an index of a vector of the 196884-diemnsional representation of the monster between internal, external, and sparse notation.
Functions
-
uint32_t mm_aux_index_extern_to_sparse(uint32_t i)
Convert an index from external to sparse representation.
The function converts an index
i
for the external representation of a vector to an index for the sparse representation of a vector and returns the converted index. The function returns 0 in casei >= 196884
`.Indices for the sparse representation are defined as in
enum MM_SPACE_TAG
in filemm_basics.h
.
-
void mm_aux_array_extern_to_sparse(uint32_t *a, uint32_t len)
Convert index array from external to sparse representation.
The function converts an array
a
of indices for the external representation to an array of indices for the sparse representation of a vector. All indices in the arraya
of lengthlen
are converted in place, using functionmm_aux_index_extern_to_sparse
.
-
int32_t mm_aux_index_sparse_to_extern(uint32_t i)
Convert an index from sparse to external representation.
The function converts an index
i
for the sparse representation of a vector to an index for the external representation of a vector and returns the converted index. The function returns -1 if the inputi
denotes an illegal index. The coordinate value encoded in the inputi
is ignored.Indices for the sparse representation are defined as in
enum MM_SPACE_TAG
in filemm_basics.h
.
-
int32_t mm_aux_index_sparse_to_leech(uint32_t i, int32_t *v)
Convert sparse index to a short vector in the Leech lattice.
The function converts an index
i
for the sparse representation of a vector to a vectorv
in the Leech lattice. This conversion is successful ifi
denotes a legal index for one of the tags tagsB, C, T, X
. Then the function computes a short Leech lattice vector (scaled to norm 32) in the arrayv
. Outputv
is determined up to sign only; that sign is implementation dependent.The function returns 0 in case of a successful conversion and -1 in case of failure.
-
uint32_t mm_aux_index_sparse_to_leech2(uint32_t i)
Convert sparse index to a short vector in the Leech lattice mod 2.
The function converts an index
i
for the sparse representation of a vector to a vectorv
in the Leech lattice mod 2. This conversion is successful ifi
denotes a legal index for one of the tags tagsB, C, T, X
. The function returns a short Leech lattice vector modulo 2, encoded in Leech lattice encoding, as described in section Description of the mmgroup.generators extension.The function returns 0 in case of failure.
-
uint32_t mm_aux_index_leech2_to_sparse(uint32_t v2)
Convert short vector in the Leech lattice mod 2 to sparse rep.
The function converts an value
v2
representing a vector in the Leech lattice mod 2 to a sparse index and returns that sparse index. It returns 0 ifv2
is not a short Leech lattice vector.
-
uint32_t mm_aux_index_intern_to_sparse(uint32_t i)
Convert an index from internal to sparse representation.
The function converts an index
i
for the internal representation of a vector to an index for the sparse representation of a vector and returns the converted index. The function returns 0 in case of a bad index.Indices for the sparse representation are defined as in
enum MM_SPACE_TAG
in filemm_basics.h
.
-
int32_t mm_aux_index_sparse_to_intern(uint32_t i)
Convert an index from sparse to internal representation.
The function converts an index
i
for the sparse representation of a vector to an index for the internal representation of a vector and returns the converted index. The function returns -1 if the inputi
denotes an illegal index. The coordinate value encoded in the inputi
is ignored.Indices for the sparse representation are defined as in
enum MM_SPACE_TAG
in filemm_basics.h
.
-
int32_t mm_aux_index_extern_to_intern(uint32_t i)
Convert an index from external to internal representation.
The function converts an index
i
for the external representation of a vector to an index for the internal representation of a vector and returns the converted index. The function returns -1 in casei >= 196884
.
-
int32_t mm_aux_index_check_intern(uint32_t i)
Check an index in internal representation.
The function checks an index
i
in the internal representation of a vector. Some entries of the vectors are stored at two different locations, e.g entriesA[i,j], B[i,j], C[i,j]
fori != j
.The function returns the other location of the same entry (as an index in internal representation) if there is any. It returns 0 if that entry is stored at exactly one location, and -1 if index
i
is illegal.
C interface for file mm_aux.c
File mm_aux.c
provides the basic functions for dealing with the representations of the monster group modulo various small integers p = 2**n-1
, 2 <= n <= 8
. Here the integer p
is called the modulus.
Especially, we deal with vectors in such a representation as described in The C interface of the mmgroup project, section Description of the mmgroup.mm extension.
For such a vector there is an internal representation, an external representation, and also a sparse representation, as described in the documentation mentioned above.
The functions in this file provide access to the internal representation of such a vector. The also support the conversion between the different representations of a vector.
Usually, the order of the parameters of functions in this file is:
1. Modulus p, if present
2. The input value or the input data array
3. Any parameters that do not affect the positions in the output array
4. The output data array
5. Parameters (e.g. lengths, indices) that affect the positions of the
data being modified in the output array
Among others, functions in this file use functions from file mm_index.c
for converting indices of vectors to different representations.
A vector modulo p
is organized in rows of 32 entries. In many rows only 24 of the 32 bits are used; but in some all 32 bit are used. Dtails are given in the API reference of the project.
Functions
-
uint8_t mm_aux_get_mmv(uint32_t p, uint_mmv_t *mv, uint32_t i)
Read entry at index from vector in internal representation.
The function returns the entry with index
i
of the vectormv
with modulusp
. The return value is reduced modulop
. Indexi
must be given in internal representation. The function returns garbage in case of an illegal index.
-
void mm_aux_put_mmv(uint32_t p, uint8_t value, uint_mmv_t *mv, uint32_t i)
Write entry to a vector at an index in internal representation.
The function sets the entry of the vector
mv
with modulusp
at the indexi
to the given value.0 <= value <= p
must hold.Here the index
i
must be given in internal representation. Writing at an illegal index performs no action.
-
void mm_aux_add_mmv(uint32_t p, uint8_t value, uint_mmv_t *mv, uint32_t i)
Add to entry of a vector at an index in internal representation.
The function adds the given value to the entry of the vector
mv
with modulusp
at the indexi
. Here0 <= value <= p
must hold.The index
i
must be given in internal representation. Writing at an illegal index performs no action.
-
void mm_aux_read_mmv32(uint32_t p, uint_mmv_t *mv, uint32_t i, uint8_t *b, uint32_t len)
Read entries from vector in internal representation.
Read entries of vector
mv
(stored in internal representation with modulusp
) and store these entries in the arrayb
. Herelen
is the number of rows to be read starting at rowi
. Each row consists of 32 entries.Here
p
must be a legal modulus.
-
void mm_aux_write_mmv32(uint32_t p, uint8_t *b, uint_mmv_t *mv, uint32_t i, uint32_t len)
Write data to a vector in internal representation.
Write data from the array
b
to the vectormv
(stored in internal representation with modulusp
). Herelen
is the number of rows to be read starting at rowi
. Each row consists of 32 entries.Here
p
must be a legal modulus.
-
void mm_aux_read_mmv24(uint32_t p, uint_mmv_t *mv, uint32_t i, uint8_t *b, uint32_t len)
Read rows of length 24 from vector in internal representation.
Read entries of vector
mv
with modulusp
and store these entries in the arrayb
, , starting at rowi
. Heremv
is a vector of rows of 24 entries, with 8 entries slack after each row.len
is the number of such rows to be read. So altogether 24 *len
entries are read frommv
and written to arrayb
; the 8 bytes slack after each 24-byte row are dropped. Vectorb
is reduced modulop
.Here
p
must be a legal modulus.
-
void mm_aux_write_mmv24(uint32_t p, uint8_t *b, uint_mmv_t *mv, uint32_t i, uint32_t len)
Write rows of length 24 to vector in internal representation.
Write data from the array
b
to the vectormv
with modulusp
. We take24 * len
bytes from the arrayb
and write them to the vectormv
, starting at rowi
. Heremv
is considered as a vector of rows of 24 entries, with 8 entries slack after each row; solen
is the number of such 24-byte rows to be written. The entries in the slack after each row written tomv
are set to zero.Here
p
must be a legal modulus.
-
uint32_t mm_aux_mmv_size(uint32_t p)
Return the size of a vector in internal representation.
The function returns the number of integers of type
uint_mmv_t
required to store a vector of the representation \(\rho_p\) (in internal representation) with modulusp
.The function returns 0 if
p
is illegal modulus.
-
uint32_t mm_aux_int_fields(uint32_t p)
Return number of entries stored in integer of type
uint_mmv_t
The function returns the number of entries of a vector of the representation \(\rho_p\) (in internal representation) that can be stored in an integer of type
uint_mmv_t
.The function returns 0 if
p
is illegal modulus.
-
uint32_t mm_aux_v24_ints(uint32_t p)
Return number of integers of type
uint_mmv_t
to store 24 entries.The function returns the number of integers of type
uint_mmv_t
required to store a part of 24 entries of a vector of the representation \(\rho_p\) (in internal representation) with modulusp
. Such parts of 24 entries arise naturally in the construction of \(\rho_p\).The function returns 0 if
p
is illegal modulus.
-
void mm_aux_zero_mmv(uint32_t p, uint_mmv_t *mv)
Zero a vector in internal representation.
The function sets all entries of the vector
mv
with modulusp
in internal representation to zero.
-
void mm_aux_random_mmv(uint32_t p, uint_mmv_t *mv, uint64_t *seed)
Randomize a vector in internal representation.
The function randomizes all entries of the vector
mv
with modulusp
in internal representation uniformly using the internal random generator in filegen_random.c
. Parameterseed
must be a seed for a random generator as described in filegen_random.c
.
-
int32_t mm_aux_reduce_mmv(uint32_t p, uint_mmv_t *mv)
Reduce a vector in internal representation.
The function reduces all entries of the vector
mv
with modulusp
in internal representation to a standard form, so that equal vectors are represented by equal arrays of integers.Note that a zero entry in such a vector can be represented either by the bit string
0...0
or by1...1
. This functions sets all zero entries of the vector to0...0
.The function returns 0 if it detects no error. It may return the following error codes:
-1: Bad modulus
p
-2: A one bit outside a valid bit field for an entry has been found
-
int32_t mm_aux_reduce_mmv_fields(uint32_t p, uint_mmv_t *mv, uint32_t nfields)
Auxiliary function of function
mm_aux_reduce_mmv
The function performs the same operation as function
mm_aux_reduce_mmv
. But instead of all entries of the vectormv
, it reduces the firstlen
entries only.
-
int32_t mm_aux_check_mmv(uint32_t p, uint_mmv_t *mv)
Check a vector in internal representation for errors.
The function checks all entries of the vector
mv
with modulusp
in internal representation for errors. It returns 0 if it detects no error. It may return the following error codes:-1: Bad modulus
p
-2: A one bit outside a valid bit field for an entry has been found
-3: A subfield of 24 entries has an illegal nonzero entry at index >= 24
-4: The vector has an illegal nonzero diagonal entry
-5: The symmetric part of the vector is not actually symmetric
As a side effect,
mv
is reduced with functionmm_aux_reduce_mmv
.
-
void mm_aux_small24_expand(uint8_t *b_src, uint8_t *b_dest)
Convert part of vector from external to internal representation.
Conversion between the internal and the external representation of a vector is straightforward, except for entries with tags
A, B, C
. The entries with these tags are stored in the first 852 entries of the external representation. In the internal representation the entries with these tags are spread over three symmetric 24 times 24 times matrices.This function maps the 852 entries of the array
b_src
(corresponding to tagsA, B, C
) to the arrayb_dest
of size 3 * 24 * 24 (corresponding to three symmetric 24 times 24 times matrices). Functionmm_aux_write_mmv24
can be used to write the data from the arrayb_dest
to the initial segment of the internal representation of a vector.
-
void mm_aux_small24_compress(uint8_t *b_src, uint8_t *b_dest)
Convert part of vector from internal to external representation.
Conversion between the internal and the external representation of a vector is straightforward, except for entries with tags
A, B, C
. The entries with these tags are stored in the first 852 entries of the external representation. In the internal representation the entries with these tags are spread over three symmetric 24 times 24 times matrices.This function maps the 3 * 24 * 24 entries of the array
b_src
(corresponding to three symmetric 24 times 24 times matrices) to the 852 entries of the arrayb_dest
(corresponding to tagsA, B, C
in external representation).This reverses the effect of function
mm_aux_small24_expand
. Functionmm_aux_read_mmv24
can be used to read the data from the initial segment of the internal representation of a vector to the arrayb_src
, before calling this function.
-
void mm_aux_mmv_to_bytes(uint32_t p, uint_mmv_t *mv, uint8_t *b)
Convert vector from internal to external representation.
Read all entries of vector
mv
(stored in internal representation with modulusp
) and store these entries in the arrayb
in external representation.Output vector
b
is reduced modulop
. It must have length 196884.
-
void mm_aux_bytes_to_mmv(uint32_t p, uint8_t *b, uint_mmv_t *mv)
Convert vector from external to internal representation.
Read all entries of the array `
b
(of length 196884, containing a vector in external representation) and store these entries the vectormv
. Heremv
is a vector stored in internal representation with modulusp
.Any entry
x
in the arrayb
must satisfy0 <= x <= p
. The vectormv
is an array ofn
integers of typeuint_mmv_t
withn = mm_aux_mmv_size(p)
.
-
int32_t mm_aux_mmv_to_sparse(uint32_t p, uint_mmv_t *mv, uint32_t *sp)
Convert vector from internal to sparse representation.
Read all entries of vector
mv
(stored in internal representation with modulusp
) and store these entries in the arraysp
in sparse representation. Each entry in the arraysp
represents a nonzero entry of the vector. The function returns the length of the output arraysp
or an negative value in case of error. Negative return values are as in functioncheck_mmv_buffer
.Output vector
sp
is reduced modulop
. The buffer for arraysp
must have length 196884. Input vectormv
is checked with functioncheck_mmv_buffer
.
-
void mm_aux_mmv_extract_sparse(uint32_t p, uint_mmv_t *mv, uint32_t *sp, uint32_t length)
Extract entries from a vector in internal representation.
The function extracts certain entries from the vector
mv
depending on the vectorsp
. Heremv
is a vector stored in internal representation with modulusp
. Vectorsp
is a vector of lengthlength
in sparse representation.The entries of vector
sp
are updated with the corresponding entries ofmv
. Ifsp
has an entry with a certain label then the coordinate of that entry is set to the corresponding coordinate of vectormv
. If several entries ofsp
have the same label then the same coordinate is taken frommv
several times.Bit 7,…,0 of any entry of
sp
should be either 0 or p. If that value is 0 then the coordinate is read to bits 7,…,0 of that entry. If that entry isp
then the negative coordinate is read instead. Other values of these bits are strongly discouraged; but technically we XOR the corresponding coordinate of vectormv
to these bits; and we then change a resultp
to zero. There is a special case where this detail is relevant.
-
uint32_t mm_aux_mmv_get_sparse(uint32_t p, uint_mmv_t *mv, uint32_t sp)
Extract one entry of a vector in internal representation.
The statement
uint32_t sp1 = mm_aux_mmv_get_sparse(p, mv, sp);
is equivalent touint32_t sp1 = sp; mm_aux_mmv_extract_sparse(p, mv, &sp1, 1);
-
void mm_aux_mmv_add_sparse(uint32_t p, uint32_t *sp, uint32_t length, uint_mmv_t *mv)
Add vector in sparse rep to vector in internal representation.
The function adds a vector
sp
in sparse representation to a vectormv
in internal representation with modulusp
. Vectorsp
has lengthlength
, and each valuex
in an entry of vectorsp
must satisfy0 <= x <= p
. Different entries insp
with the same index are added up.
-
void mm_aux_mmv_set_sparse(uint32_t p, uint_mmv_t *mv, uint32_t *sp, uint32_t length)
Set certain entries of a vector in internal representation.
The function sets certain entries of the vector
mv
depending on the vectorsp
. Vectormv
is given in internal representation with modulusp
. Vectorsp
is given in sparse representation and has lengthlength
.If
sp
has an entry with a certain label then the corresponding entry ofmv
is set to to the value coded in that entry ofsp
. Each of these valuesx
must satisfy0 <= x <= p
. Duplicate entries insp
with the same label and different values are illegal; in that case the value ofmv
is undefined.
-
int32_t mm_aux_mmv_extract_sparse_signs(uint32_t p, uint_mmv_t *mv, uint32_t *sp, uint32_t n)
Extract signs of a vector in internal representation.
The function extracts the signs of certain entries of the vector
mv
depending on the vectorsp
. Vectormv
is given in internal representation with modulusp
. Vectorsp
is given in sparse representation and has lengthn
.Entry
sp[i]
specifies a multiplec[i] * u[i]
of a unit vectoru[i]
. Letm[i]
be the coordinate of vectormv
with respect to the unit vectoru[i]
. We puts[i] = 0
ifm[i] = c[i]
ands[i] = 1
ifm[i] = -c[i]
. In all other cases we assign a random value 0 or 1 tos[i]
. Then the function returns the sum of the valuess[i] << i
, wherei
ranges from0
ton - 1
.
-
int32_t mm_aux_mmv_extract_x_signs(uint32_t p, uint_mmv_t *mv, uint64_t *elem, uint32_t *a, uint32_t n)
Extract some bits of a vector in internal representation.
The function extracts the least significant bits of certain entries of the vector
mv
depending on the vectora
. Vectormv
is given in internal representation of the Monster with modulusp
.Vector
a
is a an array ofn
elements of the groupQ_x0
of structure \(2^{1+24}\), with each element given in Leech lattice encoding. Here each element ofQ_x0
must correspond to a Leech lattice vector of type 2; otherwise the function fails.The array
elem
represents an element of the groupG_x0
of structure \(2^{1+24}.\mbox{Co}_1\), given in G_x0 representation. Internally, the function transforms (i.e. conjugates) all elements ofQ_x0
in the arraya
with the elementelem
, i.e. it calculates the elementa'[i] = elem^-1 * a[i] * elem
ofQ_x0
. Then it extracts the least significant bitb[i]
of the entry of the vectormv
with the coordinate labelled bya'[i]
.Note that negating
a'[i]
corresponds to negating the coordinate with labela'[i]
in the vectormv
. Hence when negatinga'[i]
we also have to flip the bitb[i]
. The function fails in casea'[i] = 0
.The function returns the sum of the values
b[i] << i
, wherei
ranges from0
ton - 1
. The function also fails in casei > 31
. It returns a negative value in case of failure.Assume that a vector
mv' = mv * q * g
is given with a known vectormv
, a knowng
inG_x0
, and an unknownq
inQ_x0
. Then the main use case of this function is to find the elementq
(up to sign) without modifyingmv'
.
-
int32_t mm_aux_mul_sparse(uint32_t p, uint32_t *sp, uint32_t length, int64_t f, uint32_t p1, uint32_t *sp1)
Scalar multiplication and modular reduction in sparse representation.
The function multiplies a vector
sp
in sparse representation with a factorf
and reduces the result modulo a numberp1
.The vector
sp
has lengthlength
and is stored in sparse representation as a vector modulo an odd number2 < p < 256
. The result is reduced modulo the numberp1
and stored in sparse representation in the arraysp1
.The number
p1
must be odd and satisfy2 < p < 256
. In casef != 0
the numberp1
must dividep * abs(f)
.The function returns the length of the array
sp1
in case of success and-1
in case of failure.The two arrays
sp
andsp1
may be non overlapping or equal.
-
int32_t mm_aux_get_mmv_leech2(uint32_t p, uint_mmv_t *mv, uint32_t v2)
Read entry from vector in internal rep indexed by Leech lattice.
The function returns the entry with index
i
of the vectormv
with modulusp
. Herei
must be an index referring to a vector of type 2 in the Leech lattice modulo 2 in Leech lattice encoding. The sign bit 24 ofi
is evaluated as expected. The return value is reduced modulop
.The function returns a negative value if
i
is not a vector of type 2 in the Leech lattice modulo 2 orp
is not a legal modulus.
-
uint64_t mm_aux_hash(uint32_t p, uint_mmv_t *mv)
Compute hash value of vector in internal.
The function returns a hash value of the vector
mv
with modulusp
. It also tries to distinguish between different sparse vectors. Therefore it tries to hash over about 100 nonzero integers of typeuint_mmv_t
. So ifmv
is sparse then the function might have to scan considerably more zero entries.
C interface for file mm_tables.c
File mm_tables.c
contains functions for supporting the operations \(x_\epsilon x_\pi\) and \(y_f x_e x_\epsilon\) on the vectors of the 198884-dimesional represention \(\rho_p\) modulo a small number \(p\). These operations are implemented in separate packages for the differnet values of \(p\). But there are commom preprocessing steps required for all values \(p\). These common preprocessing steps are implemented here.
The monomial operations \(x_\epsilon, x_\pi, y_f, x_e\) are as defined in the API Reference, section The monster group. Here \(\epsilon\) is an element of the Golay cocode represented as a 12-bit integer. \(f\) and \(e\) are elements of the Parker loop represented as 13-bit integers. \(\pi\) is a automorphism of the Parker loop. In the API Reference, section Automorphisms of the Parker loop we number a certain set of these automorphisms in the same way as the elements of the Mathieu group \(M_{24}\). We denote such an automorphism \(\pi\) by its number.
Functions
-
void mm_sub_prep_pi(uint32_t eps, uint32_t pi, mm_sub_op_pi_type *p_op)
Compute information for operation \(x_\epsilon x_\pi\).
Given an element \(x_\epsilon x_\pi\) of the monster by parameters
eps
andpi
, the function computes the relevant data for performing that operation on the representation of the monster. These data are stored in the structure of typemm_sub_op_pi_type
referred by parameterp_op
.Caution:
Component
p_op->tbl_perm64
must be initialized with an array of typemm_sub_op_pi64_type a_tbl_perm64[759]
befor aclling this function!!!.
-
int32_t mm_sub_test_prep_pi_64(uint32_t eps, uint32_t pi, uint32_t *p_tbl)
For internal use only!
This is an auxiliary function for testing function
mm_sub_prep_pi
.Given
eps
andpi
as in functionmm_sub_prep_pi
, this function executes functionmm_sub_prep_p(eps, pi, p_op)
and stores the outputp_op->tbl_perm64
(as an array of length 759 * (1 + 6)) in the array referred byp_tbl
.
-
void mm_sub_prep_xy(uint32_t f, uint32_t e, uint32_t eps, mm_sub_op_xy_type *p_op)
Compute information for operation \(y_f x_e x_\epsilon\).
Given an element \(y_f x_e x_\epsilon\) of the monster by parameters
f
,e
, andeps
, the function computes the relevant data for performing that operation on the representation of the monster. These data are stored in the structure of typemm_sub_op_xy_type
referred by parameterp_op
.Caution!
Component
p_op->sign_XYZ
must either be NULL or refer to an array of typeuint8_t
of length 2048. Componentp_op->s_T
must either be NULL or refer to an array of typeuint8_t
of length 759.
Variables
-
const uint8_t MM_SUB_OCTAD_ELEMENT_TABLE[759 * 8]
For
0 <= i < 759
, the entries8*i,...8*i+7
in the tableMM_SUB_OCTAD_ELEMENT_TABLE
are the bit positions of the octad with the numberi
(in natural order).
C interface for file mm_op_p_vector.c
File mm_op_p_vector.c
implements the operation of the Monster group on a vector in the representation \(\rho_p\) of the Monster modulo \(p\).
The representation \(\rho_p\) is equal to the 196884-dimensional representation \(\rho\) of the monster, with coefficients taken modulo \(p\), as defined in section The representation of the monster group in the API reference.
Unless otherwise stated, the first parameter of a function in this module is the modulus \(p\), and that modulus must be one of the values 3, 7, 15, 31, 127, or 255.
An element of \(\rho_p\) is implemented as an array of integers of type uint_mmv_t
as described in section Description of the mmgroup.mm extension in this document.
The number of entries of a vector of type uint_mmv_t[]
for modulus \(p\) is equal to mm_aux_mmv_size(p)
.
Functions
-
int32_t mm_op_copy(uint32_t p, uint_mmv_t *mv1, uint_mmv_t *mv2)
Copy vector
mv1
in \(\rho_p\) tomv2
Here modulus
p
must be one of the values 3, 7, 15, 31, 127, or 255.
-
int32_t mm_op_compare_len(uint32_t p, uint_mmv_t *mv1, uint_mmv_t *mv2, uint32_t len)
Compare arrays
mv1
andmv2
of integers.The function compares parts of the two vectors
mv1
andmv2
of the representation \(\rho_p\).Here the function compares
len
integers of typeuint_mmv_t
starting at the pointersmv1
andmv2
. These integers are interpreted as arrays of bit fields containing integers modulo p.The function returns 0 in case of equality and 1 otherwise.
Here modulus
p
must be one of the values 3, 7, 15, 31, 127, or 255.
-
int32_t mm_op_compare(uint32_t p, uint_mmv_t *mv1, uint_mmv_t *mv2)
Compare vectors
mv1
andmv2
of \(\rho_p\).The function compares two vectors
mv1
andmv2
of the representation \(\rho_p\).It returns 0 in case of equality and 1 otherwise.
Here modulus
p
must be one of the values 3, 7, 15, 31, 127, or 255.
-
int32_t mm_op_checkzero(uint32_t p, uint_mmv_t *mv)
Check if a vector
mv
in \(\rho_p\) is zero.The function checks it the vector
mv
in the representation \(\rho_p\) is zero.It returns 0 in case
mv == 0
and 1 otherwise. It is optimized for the case thatmv
is expected to be zero.Here modulus
p
must be one of the values 3, 7, 15, 31, 127, or 255.
-
int32_t mm_op_vector_add(uint32_t p, uint_mmv_t *mv1, uint_mmv_t *mv2)
Add vectors
mv1
andmv2
of \(\rho_p\).The function adds the two vectors
mv1
andmv2
of the representation \(\rho_p\) and stores the result in the vectormv1
.Here modulus
p
must be one of the values 3, 7, 15, 31, 127, or 255.
-
int32_t mm_op_scalar_mul(uint32_t p, int32_t factor, uint_mmv_t *mv1)
Multiply vector
mv1
of \(\rho_p\) with scalar.The function multiplies the vector
mv1
of the representation \(\rho_p\) and with the (signed) integerfactor
and stores the result in the vectormv1
.Here modulus
p
must be one of the values 3, 7, 15, 31, 127, or 255.
-
int32_t mm_op_compare_mod_q(uint32_t p, uint_mmv_t *mv1, uint_mmv_t *mv2, uint32_t q)
Compare two vectors of \(\rho_p\) modulo \(q\).
The function compares two vectors
mv1
andmv2
of the representation \(\rho_p\) modulo a number \(q\). Here \(q\) should divide \(p\).It returns 0 in case of equality, 1 in case of inequality, and 2 if \(q\) does not divide \(p\).
Here modulus
p
must be one of the values 3, 7, 15, 31, 127, or 255.
-
int32_t mm_op_store_axis(uint32_t p, uint32_t x, uint_mmv_t *mv)
Set a vector in \(\rho_p\) to an axis.
Let
x
be an element of the subgroup \(Q_{x0}\) if the Monster that maps to a short Leech lattice vector. Herex
must be given in Leech lattice encoding as in the Description of the mmgroup.generators extension in the documentation of the C interface.Then
x
corresponds to vector in \(\rho_p\) that is called a 2A axis. The function stores that 2A axis inmv
.Here modulus
p
must be one of the values 3, 7, 15, 31, 127, or 255.
-
int32_t mm_op_pi(uint32_t p, uint_mmv_t *v_in, uint32_t delta, uint32_t pi, uint_mmv_t *v_out)
Compute automophism of the Parker loop on a vector.
File
mm_op_pi.c
implements the operation of the generators \(x_\pi\) and \(x_\delta\) of the monster group on a vector in the representation \(\rho_p\) of the Monster modulop
. Herep
must be 3, 7, 15, 31, 127, or 255.Here generators \(x_\pi\) and \(x_\delta\) are defined as automorphisms of the Parker loop as in section The monster group of the API reference. An automophism of the Parker loop is specified by a pair of integers
d, pi
as in the constructor of the Python classAutPL
, see section Automophisms of the Parker loop in the API reference.The exact operation of an automorphism of the Parker loop on \(\rho\) is as defined in [Seysen19].
Note that the integers
d, pi
mentioned above describe the number of an element of the Golay cocode and the number of a permutation in the Mathieu group \(M_{24}\), respectively. Internally, we use the C functions in filemat24_functions.c
and the functionmm_sub_prep_pi
in filemm_tables.c
for converting the integersd, pi
to mathematical objects that can be used for implementing the operation on \(\rho_p\). These conversions are very fast compared to the cost for the operation on \(\rho_p\). This helps us to keep the C interface for these operations simple.Let
v_in
be a vector of the representation \(\rho_p\) of the monster group. Then the function computes this automorphism on the input vectorv_in
and stores the result in the output vectorv_out.
Input vectorv_in
is not changed.Here modulus
p
must be one of the values 3, 7, 15, 31, 127, or 255.
-
int32_t mm_op_xy(uint32_t p, uint_mmv_t *v_in, uint32_t f, uint32_t e, uint32_t eps, uint_mmv_t *v_out)
Compute an operation of the monster group on a vector.
Let
v_in
be a vector of the representation \(\rho_p\) of the monster group.The function implements the operation of the element \(y_f \cdot x_e \cdot x_\epsilon\) of the monster group on a vector
v_in
in the representation \(\rho_p\) of the monster.The integers
f
ande
occuring in the generators \(y_f\) and \(x_e\) encode elements of the Parker loop. The integereps
encodes the element \(\epsilon\) of the Golay cocode occuring in the generator \(x_\epsilon\), as indicated in the header of this file. The function computes this operation of the element of the monster (given by parametersf, e, eps
) on the input vectorv_in
and stores the result in the output vectorv_out.
Input vector
v_in
is not changed.Here modulus
p
must be one of the values 3, 7, 15, 31, 127, or 255.
-
int32_t mm_op_omega(uint32_t p, uint_mmv_t *v, uint32_t d)
Compute an operation of the monster group on a vector.
Let
v
be a vector of the representation \(\rho_p\) of the monster group.The function implements the operation of the element \(x_d\) of the monster group on a vector
v
in the representation \(\rho_p\) of the monster. Hered
must be one of the integers0, 0x800, 0x1000
, or0x1800
, encoding the generators \(x_1, x_\Omega, x_{-1}\), or \(x_{-\Omega}\), respectively.The function computes the operation \(x_d\) on the vector
v
and overwrites the vectorv
with the result. The function can be considered as a simplified (and much faster) version of functionmm_op_xy
.Here modulus
p
must be one of the values 3, 7, 15, 31, 127, or 255.
-
int32_t mm_op_t_A(uint32_t p, uint_mmv_t *v_in, uint32_t e, uint_mmv_t *v_out)
Compute part A of operation of \(\tau^e\) on vector``.
Function
mm_op_t_A
computes a the operation of the monster group element \(\tau^e\) on a vectorv_in
and stores the A part of the result in a vectorv_out
. That operation depends on a parametere
. The other entries of vectorv_out
are not changed. See section The representation of the monster group in the API reference for tags of entries of a vector in the representation of the monster. Note that the entries of vectorv_out
with tagA
also depend on entries of vectorv_in
with tags different fromA
.Here modulus
p
must be one of the values 3, 7, 15, 31, 127, or 255.
-
int32_t mm_op_word(uint32_t p, uint_mmv_t *v, uint32_t *g, int32_t len_g, int32_t e, uint_mmv_t *work)
Compute operation of the monster group on a vector.
Let \(v\) be a vector of the representation \(\rho_p\) of the monster group stored in the array referred by
v
.Let \(g\) be the element of the monster group stored in the array of length
len_g
referred by the pointerg
.Then the function computes the vector \(v \cdot g^e\) and overwrites the vector in the array
v
with that vector. Here \(e\) is the exponent given by the integere
.The function requires a work buffer (referrd by
work
), which is an array ofmm_aux_mmv_size(p)
entries of typeuint_mmv_t
. So the work buffer has the same size as the vectorv
.The function returns 0 in case of success and a nonzero value in case of failure.
Internally, the function simplifies all substrings of the string representing the word \(g^e\), except for atoms corresponding to nonzero powers of the generator \(\xi\). So the user need not ‘optimize’ the input \(g\). Of course, this simplification does not change the input array
g
.Here modulus
p
must be one of the values 3, 7, 15, 31, 127, or 255.
-
int32_t mm_op_word_tag_A(uint32_t p, uint_mmv_t *v, uint32_t *g, int32_t len_g, int32_t e)
Restriction of function
mm_op_word
to tagA
Function
mm_op_word
computes the operation of an element \(h = g^e\) of the monster group a vectorv
and overwritesv
with the result of that operation. \(h\) depends on parametersg, len_g,
ande
of this function.Function
mm_op_word_tag_A
computes the same automorphism on the entries of the vectorv
with tagA
only, and ignores the other entries ofv
. See section The representation of the monster group in the API reference for tags of entries of a vector in the representation of the monster.The function overwrites the vector
v
with the result. Here only entries ofv
with tagA
are changed.Parameters and return value are the same as in function
mm_op_word
, except that a work buffer is not required here. Also, the function fails and returns a nonzero value, if the word that makes up the group element \(h\) contains any nonzero powers of the generator \(\tau\) of the monster group. Note that such a power of \(\tau\) does not fix the the part of the vectorv
with tagA
. Powers of the generator \(\tau\) correspond to atoms with tagt
.This function is much faster than function
mm_op_word
. Arrayv
must have24 * mm_aux_v24_ints(p)
entries of typeuint_mmv_t
.Here modulus
p
must be one of the values 3, 7, 15, 31, 127, or 255.
-
int32_t mm_op_word_ABC(uint32_t p, uint_mmv_t *v, uint32_t *g, int32_t len_g, uint_mmv_t *v_out)
Compute ABC part of the operation of the monster group on a vector.
Let \(v\) be a vector of the representation \(\rho_p\) of the monster group stored in the array referred by
v
.Let \(g\) be the element of the monster group stored in the array of length
len_g
referred by the pointerg
. Here \(g\), and also all prefixes of the word representing \(g\), must be in the set \(G_{x0} \cdot N_0\).The function computes the parts with tags
A
,B
, andC
of the vector \(v \cdot g\) and stores the result in the arrayv_out
. The other parts of the vector \(v \cdot g\) are not computed. Here the arrayv_out
must have72 * mm_aux_v24_ints(p)
entries of typeuint_mmv_t
.This function is much faster than function
mm_op_word
. It is mainly used for dealing with a 2A axis \(v\).Here modulus
p
must be one of the values 3, 7, 15, 31, 127, or 255.
-
int32_t mm_op_scalprod(uint32_t p, uint_mmv_t *v1, uint_mmv_t *v2)
Compute the scalar product of two vectors.
Let \(v_1, v_2\) be vectors of the representation \(\rho_p\) of the monster group stored in the array referred by
v1, v2
.The function returns the scalar product \((v_1, v_2)\) (reduced modulo \(p\)) in case of success and a negative value in case of failure.
Here modulus
p
must be one of the values 3, 7, 15, 31, 127, or 255.
Variables
-
const uint8_t MM_OP_P_TABLE[] = {0x03, 0x07, 0x0f, 0x1f, 0x7f, 0xff, 0x00}
Table of legal moduli
p
, terminted by zero.
C interface for file mm_op_p_axis.c
File mm_op_p_axis.c
implements the operation of the Monster group on a vector in the representation \(\rho_p\) of the Monster modulo \(p\). In this module such a vector is usually a 2A axis.
The representation \(\rho_p\) is equal to the 196884-dimensional representation \(\rho\) of the monster, with coefficients taken modulo \(p\), as defined in section The representation of the monster group in the API reference.
The first parameter of a function in this module is the modulus \(p\), and that modulus must be one of the values specified in the function.
An element of \(\rho_p\) is implemented as an array of integers of type uint_mmv_t
as described in section Description of the mmgroup.mm extension in this document.
The number of entries of a vector of type uint_mmv_t[]
for modulus \(p\) is equal to mm_aux_mmv_size(p)
.
Functions
-
int32_t mm_op_load_leech3matrix(uint32_t p, uint_mmv_t *v, uint64_t *a)
Load the ‘A’ part of a vector of the representation of the monster.
The function loads the part of with tag ‘A’ of a vector
v
of the representation of the monster modulop
to the matrixa
. Here matrixa
will be given in matrix mod 3 encoding as documented in the header of fileleech3matrix.c
.Here modulus
p
must be one of the values 3, or 15.
-
int64_t mm_op_eval_A_rank_mod3(uint32_t p, uint_mmv_t *v, uint32_t d)
Rank of ‘A’ part of a vector of the representation of the monster.
Let
a
be the symmetric 24 times matrix corresponding to the part with tag ‘A’ of a input vectorv
in the representation of the monster modulop
. Letb = a - d * 1
, for an integer inputd
, where1
is the unit matrix.Let
r
be the rank of matrixb
with entries taken modulo 3. If matrixb
has rank 23 then its kernel is one dimensional. In that case the kernel contains two nonzero vectors+-w
, and we definew
to be one of these vectors. Otherwise we letw
be the zero vector.The function returns the value
(r << 48) + w
, withw
the vector defined above given in Leech lattice mod 3 encoding as described in The C interface of the mmgroup project.The number of entries of parameter
v
for modulus \(p\) is equal to24 * mm_aux_int_fields(p)
.Here modulus
p
must be 3, or 15.
-
int32_t mm_op_eval_A_aux(uint32_t p, uint_mmv_t *v, uint32_t m_and, uint32_t m_xor, uint32_t row)
Auxiliary function for
mm_op_eval_A
Let matrix
A
be the part with tag ‘A’ of a vectorv
of the representation of the monster modulop
}.Let
m_and[i]
andm_xor[i]
be the biti
ofm_and
andm_xor
, respectively. Define a vectory = (y[0],...,y[23])
by:y[i] = m_and[i] * (-1)**m_xor[i]
.If
row >= 24
the function returnsres = y * A * transpose(y)
(modulop
). We have0 < res < 0x8000
, butres
is not reduced modulop
.In case
row < 24
define the vectorz
byz[i] = y[i]
ifi = row
andz[i] = 0
otherwise. Putzz = z * A * transpose(y)
(modulop
). We have0 < res < 0x8000
, butres
is not reduced modulop
.Here modulus
p
must be 3, or 15.
-
int32_t mm_op_eval_A(uint32_t p, uint_mmv_t *v, uint32_t v2)
Evaluate A part in rep of monster at a short Leech vector.
Let
v
be a vector in the 196884-dimensional representation of the monster group modulop
, encoded as described in section Description of the mmgroup.mm<p> extensions in the description of the C interface. The entries corresponding to tag ‘A’ ofv
form a symmetric 24 times 24 matrix \(A\).Let \(v_2\) be a short Leech lattice vector given by parameter
v2
, encoded as a vector in the Leech lattice modulo 2. Then \(v_2\) is determined up to sign and \(v_2 A v_2^\top\) is determined uniquely.The function returns \(r = v_2 A v_2^\top\) modulo
p
, with \(0 \leq r < p\) in case of success. It returns -1 if \(v_2\) is not short (i.e. not of type 2).The short Leech lattice vector \(v_2\) (of norm 4) is scaled to norm 32 as usual, when \(v_2\) is given in integer coordinates.
Here modulus
p
must be 3, or 15.
-
int32_t mm_op_norm_A(uint32_t p, uint_mmv_t *v)
Compute norm of the ‘A’ part of a vector in the rep of the monster.
Assume that
v
is a vector in the representation of the monster modulop
. Then the part ofv
with tag ‘A’ is considered as a symmetric 24 times 24 matrix. The function returns the norm (i.e. the sum of the squares of the entries) of that matrix.Here modulus
p
must be 3, or 15.
-
int32_t mm_op_watermark_A(uint32_t p, uint_mmv_t *v, uint32_t *w)
Watermark ‘A’ part of a vector of the representation of the monster.
Let matrix
A
be the part with tag ‘A’ of a vectorv
of the representation of the monster modulop
.Then we watermark 24 the rows of matrix
A
. For each of the rowsA[i], 0 <= i < 24
we compute a watermarkw(i)
in the arrayw
. Note that the watermarkw(i)
contains an information about the marked rowi
in its lower bits. We store the sorted array of these watermarks in the arrayw
of lengthIf all these watermarks (ignoring the information about the row) are different, we can easily recognize a permutation of the rows of matrix
A
by comparing the watermark of matrixA
with the watermark of the permuted matrixA
.
The watermark
w[i]
depends on the distribution of the absolute values of the entriesw[i, j]
(modulop
) of rowi
. Thus permutations of the columns and sign changes in the matrix do not affect these watermarks.The function returns 0 in case of success and a negative value in case of error.
When working in the representation modulo
p = 3
we fail unless at least nine rows ofA
have a unique watermark. This is sufficient for reconstructing a permutation in the Mathieu group.In the other cases the watermark of row \(i\) is equal to \(i + 32\cdot S(A,i)\). Here \(S(A,i)\) depends on the entries of matrix
A
. The value \(S(A,i)\) it is invariant under sign changes of any off-diagonal elements ofA
. It is also invariant under any permutation of the symmetric matrixA
fixing row and column \(i\).We assert that watermarking
A + k*I
succeeds if and only if watermarkingA
succeeds, for any multiplek*I
of the unit matrix.Here modulus
p
must be 3, or 15.
-
int32_t mm_op_watermark_A_perm_num(uint32_t p, uint32_t *w, uint_mmv_t *v)
Compute permutation from watermarks of matrices.
Let matrix
A
be the part with tag ‘A’ of a vectorv
of the representation of the monster modulop
. Letw
be the watermark of another matrixA'
which is obtained fromA
by permutations of the rows and columns, and by sign changes. Here the watermarkw
must have been computed by functionmm_op_watermark_A
.Then the function watermarks matrix
A
and computes a permutation that mapsA'
toA
. If that permutation is in the Mathieu group \(M_{24}\) then the function returns the number of that permutation, as given by functionmat24_perm_to_m24num
in filemat24_functions.c
.The function returns a nonegative permutation number in case of success and a negative value in case of error.
If all watermarks in the array
w
(ignoring the information about the row in the lower 5 bits) are different then there is at most one permutation that mapsA'
toA
. If that permutation is in \(M_{24}\) then the function returns the number of that permutation. In all other cases the function fails.In case
p = 3
we succeed already if the first 9 watermarks in the arrayw
are different. Then there is at most one permutation in \(M_{24}\) that mapsA'
toA
.Here modulus
p
must be 3, or 15.
-
int32_t mm_op_eval_X_find_abs(uint32_t p, uint_mmv_t *v, uint32_t *p_out, uint32_t n, uint32_t y0, uint32_t y1)
Find certain entries of a vector of the monster rep modulo %
p
Let
v
be a vector of the monster group representation modulo %p
. The function tries to find all entries of the monomial part ofv
with absolute valuesy0
andy1
,1 <= y0, y1 <= p / 2
. In casey1 = 0
entries with valuey1
are ignored.Here the monomial part of
v
consists of the entries with tags ‘B’, ‘C’, ‘T’, ‘X’. The coordinates of these entries correspond to the short vectors of the Leech lattice.Output is written into the array
p_out
of lengthn
. If the monomial part ofv
contains an entry with absolute valuey0
then the coordinate of that entry is written into arrayp_out
in Leech lattice encoding. If that part ofv
contains an entry with absolute valuey1
then the coordinate of that entry is witten into that array in the same encoding.In addition, for entries in
v
with absolute valuey1
the bit 24 of the corresponding entry inp_out
is set. Inp_out
, the entries with absolute valuey1
are stored after those with absolute valuey0
. Entries with the same absolute value are stored in the same order as inv
.The function returns the number of valid entries in the array
p_out
. If the lengthn
ofp_out
is too small then some entries will be dropped without notice.Here modulus
p
must be 15.
-
int32_t mm_op_eval_X_count_abs(uint32_t p, uint_mmv_t *v, uint32_t *p_out)
Count certain entries of a vector of the monster rep modulo
p
Let
v
be a vector of the monster group representation modulop
. The function counts the absolute values of all entries of the monomial part ofv
.Here the monomial part of
v
consists of the entries with tags ‘B’, ‘C’, ‘T’, ‘X’. The coordinates of these entries correspond to the short vectors of the Leech lattice.Output is written into the array
p_out
of lengthp/2 + 1
. Entryp_out[i]
contains the number if entries of the monomial part ofv
with absolute valuei
for0 <= i <= p/2 + 1
.Here modulus
p
must be 15.The function returns 0.
Internal operation
The source code for the functions in modules mm_aux.c
and mm_tables.c
is located in subdirectory
src/mmgroup/dev/mm_basics
. The code generation process
genrates .c
files from the source files with extension
.ske
in that subdirectory. Protoypes for the functions in
these .c
files can be found in file mm_basics.h
.
The source code for the functions in modules mm_op_p_vector.c
and mm_op_p_axis.c
is located in subdirectory
src/mmgroup/dev/mm_op
. The code generation process
genrates .c
files from the source files with extension
.ske
in that subdirectory. Protoypes for the functions in
these files can be found in file mm_o_p.h
.
The code gerneration process for C files derived from the source
files in the src/mmgroup/dev/mm_basics
directory is
straightforward. In the remainder of this subsection we describe
the code gerneration process for files derived form sources
in the src/mmgroup/dev/mm_op
directory.
For reasons of efficiency a dedicated set of .c
files is
generated from the .ske```files in the ``src/mmgroup/dev/mm_op
directory for each modulus p
supported. Here corresponding
.c
files for different moduli are generated from the same
source file with extension .ske
. The .c
functions in
modulea mm_op_p_vector.c
and mm_op_p_axis.c``contain
automatically-generated ``case
statements that call the working
functions for the appropriate modulus p
. Any of these .c
functions takes the modulus p
as its first argument, and
dispatches the work to the subfunction dedicated to the
appropriate modulus p
.
E.g. the function mm_op_pi
in module mm_op_p_vector.c` calls
working functions ``mm3_op_pi
, mm7_op_pi
, etc. in
case p = 3
, p = 7
, etc., for doing the actual work in the
representation of the Monster modulo p
. Such working functions
are implemented in different .c
files, with one .c
file for
each modulus. So the functions mm3_op_pi
and mm7_op_pi
are
implemented in the .c
files mm3_op_pi.c
and mm7_op_pi.c`,
respectively. Here such a .c
file may implement several working
functions for the same modules p
.
All functions exported from file mm_op_p_vector.c
support the
same set of moduli p
. Functions exported from file
mm_op_p_axis.c
deal with 2A axes; the usually support moduli
3 and 15 (or just one of these two values) only; see documentation
of the corresponding functions.
So the process of switching to the appropriate function for a given modulus is completely invisible for Python and Cython.
Basic table-providing classes for module mmgroup.mm_op
We describe the class MM_Basics
and its subclass MM_Const
Class MM_Basics
in module mmgroup.dev.mm_basics.mm_basics
defines
several constants that describe the organization of vectors of integers
modulo \(p\) used in the representation modulo \(\rho_p\). Here
several integers modulo \(p\) are stored in a single unsigned
integer of type uint_mmv_t
. Type uint_mmv_t
is equal to the
standard C integer type uint64_t
on a 64-bit system.
For a 32-bit system that type may be changed to uint32_t
by adjusting
the variable INT_BITS
in this module, but this has no longer been
tested for several years.
Name
Value
FIELD_BITS
Number of bits used to store an integer modulo
P
. This is the smallest power of two greater than or equal toP_BITS
.
INT_BITS
Number of bits available in an unsigned integer of type
uint_mmv_t
. This is equal to 64.
INT_FIELDS
Number of integers modulo
P
that is stored in a variable of typeuint_mmv_t
.INT_FIELDS
is a power of two and equal toINT_BITS/FIELD_BITS
.
LOG_FIELD_BITS
Binary logarithm of the value
FIELD_BITS
.
LOG_INT_BITS
Binary logarithm of the value
INT_BITS
.
LOG_INT_FIELDS
Binary logarithm of the value
INT_FIELDS
.
LOG_V24_INTS
Binary logarithm of the value
V24_INTS
.
LOG_V64_INTS
Binary logarithm of the value
V64_INTS
.
MVV_ENTRIES
Number of integers modulo
P
contained in a vector of the representation of the monster, including unused entries.
MVV_INTS
Number of integers of type
uint_mmv_t
required to store a vector of the representation of the monster. This value depends onP
.
P
The modulus of the current representation being generated.
P
is equal to2**P_BITS - 1
.
P_BITS
Bit length of modulus
P
.
V24_INTS
Number of integers of type
uint_mmv_t
used up to store a vector of24
integers moduloP
.V24_INTS
is always a power of two.
V64_INTS
Number of integers of type
uint_mmv_t
used to store a vector of64
integers moduloP
.V64_INTS
is always a power of two.
V64_INTS_USED
Number of integers of type
uint_mmv_t
actually used to store a vector of24
integers moduloP
. This may be less thanV24_INTS
.
Class MM_Const
in module mmgroup.dev.mm_basics.mm_basics
is
a table-providing class for the C functions used by python extension
mmgroup.mm
. Most C functions in that module take the modulus p
as
a parameter. They need fast access to the constants given in the table
above for all legal values of p
. Using the code generator with the
tables and directives provided by class MM_Const
, we can easily
obtain these values for any legal p
as in the following example:
// Return a nonzero value if p is a bad modulus,
// i.e. not p = 2**k - 1 for some 2 <= k <= 8
#define mm_aux_bad_p(p) (((p) & ((p)+1)) | (((p)-3) & ((0UL-256UL))))
// Create a precomputed table containing the constants for modulus p
// %%USE_TABLE
static const uint32_t MMV_CONST_TABLE[] = {
// %%TABLE MMV_CONST_TAB, uint32
};
int do_something_for_modulus_p(uint 32_t p, ...)
{
uint32_t modulus_data, p_bits, field_bits;
// Reject any illegal modulus p
if (mm_aux_bad_p(p)) return -1;
// Load the constants for modulus p to variable modulus_data
// %%MMV_LOAD_CONST p, modulus_data;
// Load value P_BITS for modulus P to p_bits (using modulus_data)
p_bits = %{MMV_CONST:P_BITS,modulus_data};
// Load value FIELD_BITS for modulus P to field_bits
field_bits = %{MMV_CONST:FIELD_BITS,modulus_data};
// Now do the actual work of the function using these values
...
}
- class mmgroup.dev.mm_basics.mm_basics.MM_Const(**kwds)
This is the basic table-providing class for module
mmgroup.mm
The main purpose of this class is to provide the constants defined in class
MM_Basics, for a variable modulus ``p
as shown in the example above.This class provides the directive
MMV_CONST_TAB
for generating all tables, and the directiveMMV_LOAD_CONST
for storing the table of constants, for a specific modulusp
, in an integer variable. The string formatting functionMMV_CONST
can be used for extracting a specific constant from that variable, as indicated in the example above.Internally, we use a deBruijn sequence to translate the value
p
to an index for the table generated via the directiveMMV_CONST_TAB
.Constants not depending on the modulus
p
, such asINT_BITS
,LOG_INT_BITS
, andMMV_ENTRIES
are available as attributes of classMM_Const
. They can also be coded with the code generator directly via string formatting, e.g.:uint_8_t a[%{MMV_ENTRIES}];
For a fixed modulus
p
the constants depending onp
can also be coded with the code generator via string formatting, e.g.:a >>= %{P_BITS:3};
That constant also availble in the form
MM_Const().P_BITS(3)
.Class
MM_Const
provides a string-formatting functionshl
which generates a shift expression Here:%{shl:expression, i}
generates an expression equivalent to
((expression) << i)
. Herei
must be an integer. In casei < 0
we generate((expression) >> -i)
instead. E.g.%{shl:'x',-3}
evaluates tox >> 3
.Class
MM_Const
provides another string-formatting functionsmask
which generates an integer constant to be used as a bit mask for integers of typeuint_mmv_t
. Here:%{smask:value, fields, width}
with integers
value
,fields
, andwidth
creates such a bit mask.For 0 <= i
and0 <= j < width
, the bit of that mask at positioni * width + j
is set if both, biti
of the integerfields
and bitj
of the integervalue
are set. A bit in the mask at positionINT_BITS
or higher is never set.Any of the arguments
value
andfields
may either be an integer or anything iterable that yields a list of integers. Then this list is interpreted as a list of bit positions. A bit of that argument is set if its position occurs in that list and cleared otherwise.E.g.
%{smask:3, [1,2], 4}
evaluates to0x330
.- snippet(source, *args, **kwds)
Generate a C code snippet
This method calls function
c_snippet
in modulemmgroup.generate_c
to generate a C code snippet. Parameters are as in functionc_snippet
. The method returns the generated C code snippet as a string.In addition, all tables and directives available in the given instance of the table-providing class are also passed as arguments to function
c_snippet
.
We describe the class MM_Op
.
Class MM_Op
in module mmgroup.dev.mm_op.mm_op
is a
table-providing class for the C functions used by python extensions
mmgroup.mm<p>
. Each of these extensions implements
the operation of monster group modulo a fixed number p
.
Class MM_Op
provides the same functionality as class MM_Const
in module mmgroup.dev.mm_basics.mm_basics
. Since modulus p
is fixed in an instance of class MM_Op
, all constants provided
by the base class MM_Basics
of MM_Op
and MM_Const
(see
table Constants used for generating representations of the monster)
have fixed values. So they are available as attributes of an
instance of class MM_Op
and they may also be used by the code
generator directly via string formatting.
The string formatting functions %{shl:expression,i}
and
%{smask:value, fields, width}
work as in class MM_Op
. In
addition, parameter fields
defaults to -1
(i.e. the mask
is set in all bit fields) and width
defaults to the constant
FIELD_BITS
. i.e. the number of bits used to store an integer
modulo p
. E.g. for p = 7
we have FIELD_BITS = 4
, and
%{smask:1}
evaluates to the 64
-bit integer constant
0x1111111111111111
.
Class MM_Op
also provides the following directives:
MMV_ROTL src, count, dest
Rotate the bit fields of a variable of type
uint_mmv_t
Here
src
is an integer of typeuint_mmv_t
which is interpreted as an array of bit fields, where each bit field stores a number modulop
. Then each bit field is rotated left bycount
bits. This means that the numbers in all bit fields are multiplied by2**count
.count
must be an integer. It is reduced modulo the bit length ofp
. Socount
may also be negative. The result of the rotation is written to the variabledest
which should also be of typeuint_mmv_t
.dest
defaults tosrc
.
MMV_UINT_SPREAD src, dest, value
Spread bits of an integer
src
to the bit fields ofdest
. Heresrc
may be any integer variable anddest
should be a variable of typeuint_mmv_t
. If biti
of the integersrc
is set then thei
-th bit field of variabledest
is set tovalue
; otherwise it is set to zero.value
must be an integer with0 <= value <= p
; default isp
.
- class mmgroup.dev.mm_op.mm_op.MM_Op(**kwds)
Supports basic operations on integers of type
uint_mmv_t
.Here an integer of type
uint_mmv_t
is interpreted as an array of bit fields, where each bit field stores an integer modulop
for a fixed numberp
. This class is similar to classMM_Const
in modulemmgroup.dev.mm_basics.mm_basics
, where the modulusp
may be variable.Usage of this class is documented in the module documentation.
- Parameters:
p (int) – This is the modulus
3 <= p < 256
.p + 1
must be a power of two.
Deprecated stuff
In older versions of the mmgroup
project the functionality of
the mm_op
extension was spread over several Cython
extensions
with names mm
, mm3
, mm7
, mm15
, etc. There are now
python modules emulating the functionality of these deprecated
extensions, which appear to work in Windows and Linux, but
possibly not in macOS.
Note that the modules mmgroup.mm
, mmgroup.mm3
, mmgroup.mm7
,
etc., which emulate the old functionality, are also deprecated. So the
user is strongly discouraged from using these deprecated modules.
He or she should use the mm_op
extension instead!
In older versions some python functions had to select the C function for the requested modulus, which has caused rather nasty problemes in some cases.
In the mm_op
extension each documented .c
function has
been wrapped by a Cython
function with the same name and
the same signature. In the depreceated modules naming conventions
are considerably more complicated.
Description of the mmgroup.mm_reduce
extension
The functions in this module implement the fast reduction of an
element of the monster group described in [Sey22]. There
we define a triple of vector \((v_1, v^+, v^-)\) in the
representation \(\rho_{15}\) such that an element
\(g\) of the monster van be recognized from the triple
\((v_1 \cdot g, v^+ \cdot g, v^- \cdot g)\). A precomputed
vector \(v_1\) is stored in file mm_order_vector.c
.
Module mm_order.c
contains functions for computing the
order of an element of the monster. Module mm_reduce.c
contains the function mm_reduce_M
that implements the
fast reduction algorithm in the monster group.
Generating an order vector
Python module mmgroup.dev.mm_reduce.find_order_vector
This module computes an order vector in a representation of the monster.
In [Sey22] we define a vector \(v_1\) in the representation \(\rho_{15}\) of the monster group \(\mathbb{M}\) that is used for recognizing elements of the subgroup \(G_{x0}\) of \(\mathbb{M}\). Vector \(v_1\) is also used for computing the order of an element of \(\mathbb{M}\), so we call \(v_1\) an order vector here.
\(v_1\) is constructed from two vectors \(v_{71} \in \rho_3\) and \(v_{94} \in \rho_5\) via Chinese remaindering. This module contains functions for computing vectors \(v_{71}\) and \(v_{94}\) with the properties required in [Sey22].
These computations are the most time-consuming part of the computation of \(v_1\); and we use multiprocessing for performing these computations.
All computations in the monster group are done with instances
of class MM0
, but not MM
. The reason for this is that
class MM
requires the existence of an order vector.
Header file mm_reduce.h
Yet to be documented
Typedefs
-
typedef struct gt_subword_s gt_subword_type
typedef for structure
struct gt_subword_s
-
typedef struct gt_subword_buf_s gt_subword_buf_type
typedef for structure
struct gt_subword_buf_s
-
struct mm_compress_type
- #include <mm_reduce.h>
Structure for storing an element of the Monster compactly.
A properly reduced element of the Monster stored in a structure of type
gt_word_type
may also be encoded in this structure in a more compact form. This facilitates the conversion of that element to an integer, which is out of the scope of this module.This structure may store an element of the Monster as a word of generators of shape
\[ y_f \, x_d \, x_{\delta} \, \pi \, c_1 \, \tau_1 \, c_2 \, \tau_1 \, c_3 \, \tau_3 \, \ldots \, , \]where \(d, f \in \mathcal{P}, \delta \in \mathcal{C}^*\), and \(\pi \in \mbox{Aut}_{\mbox{St}} \mathcal{P}\). Here \(\pi\) must correspond to a generator with tag
p
. See section Implementation of the generators of the monster group in the API reference for details. \(\tau_i\) is wqaul to generator \(\tau\) or to its inverse.A generator \(c_i\) is an element of the group \(G_{x0}\) referred by a 24-bit integer
c_i
. This must be one of the following:If
c_i
represents a type-4 vector in Leech lattice encoding then this encodes the element of \(G_{x0}\) computed by applying the C functiongen_leech2_reduce_type4
toc_i
.If
c_i
represents a type-2 vector in Leech lattice encoding then this encodes the element of \(G_{x0}\) computed by applying the C functiongen_leech2_reduce_type2
toc_i
.The product \(y_f \, x_d \, x_{\delta} \, \pi\) is encdoded in component
nx
, and the other generators are encdoded in the entries of componentw
, as desribed in the procedures below.For background see section Computations in the Leech lattice modulo 2 in The mmgroup guide for developers.
-
struct gt_subword_s
- #include <mm_reduce.h>
Stucture to store a subword of generators of the Monster.
This structure is required in file
mm_shorten.c
.It stores a subword of a word in the Monster in a node of a circular doubly-linked list. There is a dedicated EOF (end of file) mark in that list, in which member
eof
is set to 1; and elsewhere membereof
is set to zero. Note that standard operations like insertions and deletions are easier in a circular doubly-linked list than in a standard doubly-linked list.Member
data
contains a word \(g\) of generators of the subgroup \(G_{x0}\); and membert_exp
contains an exponent \(0 \leq e < 3\). Then the structure represents the element \(g \tau^e\) of the Monster, where \(\tau\) is the triality element in the subgroup \(N_0\) of the Monster.The length of a word in member
data
is limited to the sizeMAX_GT_WORD_DATA - 1
; and we will reduce that word using functionxsp2co1_reduce_word
in modulexsp2co1.c
if necessary. Note that memberdata
may contain atoms with tags'x', 'y', 'd', 'p', 'l'
only, and the inversion bit in such an atom is always cleared.Member
img_Omega
contains the image \(g \cdot \Omega\), where \(\Omega\) is the standard frame of the Leech lattice mod 2. Hereimg_Omega
is given in Leech lattice encoding. Memberreduced
is 1 if the word in memberdata
is reduced (by functionxsp2co1_reduce_word
) and 0 otherwise.Public Members
-
uint32_t eof
0 means standard subword, 1 means EOF mark
-
uint32_t length
Number of entries in component
data
-
uint32_t img_Omega
Image of \(\Omega\) under element.
-
uint32_t t_exp
Exponent of final tag ‘t’.
-
uint32_t reduced
True if part ‘data’ is reduced.
-
struct gt_subword_s *p_prev
Pointer to previous subword.
-
struct gt_subword_s *p_next
Pointer to previous subword.
-
uint32_t data[MAX_GT_WORD_DATA]
Element of monster group.
-
uint32_t eof
-
struct gt_subword_buf_s
- #include <mm_reduce.h>
Structure to store an array of entries of type
gt_subword_type
We allocate several entries of of type
gt_subword_type
with a single call to functionmalloc
. This saves a considerable amount of interaction with the operating system.This structure contains an array of type
gt_subword_type[]
plus the necessary bookkeeping information.Public Members
-
uint32_t capacity
max No of type
gt_subword_s
entries
-
uint32_t n_used
used No of type
gt_subword_s
entries
-
struct gt_subword_buf_s *p_next
Pointer to next buffer.
-
gt_subword_type subwords[1]
array of subwords in this buffer
-
uint32_t capacity
-
struct gt_word_type
- #include <mm_reduce.h>
Stucture to store a word of generators of the Monster.
This structure is required in file
mm_shorten.c
.It stores a word in the Monster in a circular doubly-linked list of nodes of type
gt_subword_type
. Each of these node represents subword of that word, and there is a dedicated EOF (end of file) mark in that list that marks both, the beginning and the end of the list. Memberp_end
always points to the EOF mark.The structure contains a pointer
p_node
pointing to one of the nodes of the list, which we will call the current node. Some functions in these module take a pointer to this structure, and the perform operations on the current node. The pointer may be manipulated with functiongt_word_seek
.Public Members
-
gt_subword_type *p_end
Pointer to the end mark subword.
-
gt_subword_type *p_node
Pointer to current subword.
-
gt_subword_type *p_free
Pointer to list of free subwords.
-
int32_t reduce_mode
Mode for the reduction of a word.
-
uint32_t is_allocated
1 if this structure has been allcocated
-
gt_subword_buf_type *pb0
pointer to first buffer
-
gt_subword_buf_type *pbe
pointer to last buffer
-
gt_subword_buf_type buf
1st buffer containing Array of subwords
-
gt_subword_type *p_end
C interface for file mm_order_vector.c
File mm_order_vector
contains the precomuted order_vector
and data related to that order_vector
,
It also contains functions for retrieving these data.
Functions
-
int32_t mm_order_load_tag_data(uint32_t n, uint32_t *buf, uint32_t buf_size)
Load data from tables to a buffer.
The propose of this function is to provide the information for checking the correctness of the precomuted order vector \(v_1\) stored in this module.
This function stores precomputed data in a buffer
buf
of typeuint32_t[buf_size]
, wherebuf_size
is the size of the buffer. Parametern
specifies the value to be stored in the buffer. The function returns the length of the data in buffer. If the buffer is too short for that data then the function returns -1. A size parameterbuf_size = 128
is sufficient for all cases ofn
.In case
n = 0
the function returns the arrayTAG_VECTOR
of length 97. The tag vector is documented in filemm_order.c
.In case
n > 0
the function returns data required for verifying the precomputed order vector \(v_1\). The order vector is discussed in [Sey22].In case
n = 1,2,3
the function returns the values \(g_{71} \in \mathbb{M}, v^0_{71} \in \rho_{3}, g \in \mathbb{M} \), respecively, in the internal sparse format. With these data we can compute:\(v_{71} = \sum_{i=0}^{70} v^0_{71} \cdot g_{71}^i g\pmod{3}\).
In case
n = 4
the function returns the integer \(D\) in entry 0 of the buffer. In casen = 5, 6
the function returns the values \(g_{94} \in \mathbb{M}, v^0_{94}\), respectively. With this data we can compute:\(v_{94} = \sum_{i=0}^{93} (-1)^i \cdot v^0_{94} \cdot g_{94}^i \pmod{5}\).
\(v_1 = 10 \cdot v_{71} + 6 \cdot v_{94} + 5 \cdot D \cdot 1_\rho \pmod{15}\).
Here \(1_\rho\) is defined as in [Sey22]. We can also check that the order vector \(v_1\) satisfies the properties required in [Sey22].
In case
n = 7, 8, 9
, the function returnes the partsTAGS_Y
,TAGS_X
, andTAG_SIGN
, respectively, of theTAG_VECTOR
. For a description of theTAG_VECTOR
see the description ofenum tag_offsets
in fileorder_vector.c
.
-
void mm_order_load_vector(uint_mmv_t *p_dest)
Load order vector from tables to a buffer.
The function stores the precomputed order vector \(v_1\) into the array referred by
p_dest
. That array must must be sufficiently long to store a vector of the representation \(\rho_{15}\).See [Sey22] for a decription of the properties of the vector \(v_1\) in the representation \(\rho_{15}\) of the monster group.
The standard way to obtain the number of entries of type
unint_mmv_t
required for a vector of the representation \(\rho_{15}\) is to call functionmm_aux_mmv_size(15)
in filemm_aux.c
.
-
int32_t mm_order_compare_vector(uint_mmv_t *p_v)
Compare vector with precomputed order vector.
The function compares the vector \(v\) in the representation \(\rho_{15}\) of the monster group referred by
p_v
with the precomputed order vector \(v_1\).The function returns 0 in case of equality and 1 otherwise.
-
int32_t mm_order_compare_vector_part_A(uint_mmv_t *p_v)
Compare A part of vector with precomputed order vector.
The function compares the A part the vector \(v\) in the representation \(\rho_{15}\) of the monster group referred by
p_v
with the A part of the precomputed order vector \(v_1\).The function returns 0 in case of equality and 1 otherwise.
-
uint64_t mm_order_hash_vector(uint_mmv_t *p_dest)
Return the hash value of the ordervector.
The function returns the hash value of the precomuted order vector as given by function
mm_aux_hash
in filemm_aux.c
.
C interface for file mm_order.c
File mm_order.c
contains functions for checking if an element is in the subgroup \(G_{x0}\) (or \(Q_{x0}\)) of the monster group. If this is the case, the element is expressed as a word in the generators of the corresponding subgroup.
File mm_order.c
also contains functions for computing the order of an element of the monster.
All these function use the precomputed order_vector
in file mm_order_vector.c
Enums
-
enum tag_offsets
The following enumeration contains the offsets of the (static) array
TAG_VECTOR
of unsigned 32-bit integers stored in this module. This array contains data that are required for dealing with the precomputed order vector \(v_1\) stored in this module. That order vector can be obtained by calling functionmm_order_load_vector
in modulemm_order_vector.c
. The data in the arrayTAG_VECTOR
can be obtained by calling functionmm_order_load_tag_data(0, buf, 97)
in the same module, withbuf
of typeuint32_t[97]
.The purpose of the order vector \(v_1\) is to identify an element \(g\) of the subgroup \(G_{x0}\) of the monster from \(v_1 \cdot g\), as described in [Sey22]. The basic steps of this identification process are:
Given \(v_1 \cdot g\), reduce \(g\) to an element \(g_1\) of \(N_{x0}\), see [Sey22] for background.
Given \(v_1 \cdot g_1\), reduce \(g_1 \in N_{x0}\) to \(g_2\), where \(g_2\) is in a certain 2 group of structure \(2^{1+24+11}\). Therefore we have to watermark of the A part of \(v_1 \cdot g_1\) with function
mm_op15_watermark_A
in modulemm15_op_eval_A.c
. Then we have to check that watermark against the precomputed watermark of the A part of \(v_1\) using functionmm_op15_watermark_A_perm_num
in the same module. That precomputed watermark (of length 24) is stored in the arrayTAG_VECTOR
at offsetOFS_WATERMARK_PERM
.Given \(v_1 \cdot g_2\), with \(g_2\) as above, we want to present \(g_2\) as a product of generators \(g_2 = x_d x_\delta y_e\). For computing the factor \(y_e\) we have to extract (the signs of) 11 entries of \(v_1 \cdot g_2\), with function
mm_aux_mmv_extract_sparse_signs
in modulemm_aux.c
. The coordinates and the expected values of these 11 entries are stored at theTAG_VECTOR
at offsetOFS_TAGS_Y
. Once having extracted these sign bits we have to solve the linear equation system given by the 11 entries at theTAG_VECTOR
at offsetOFS_SOLVE_Y
. This solution gives the value \(e\) of the factor \(y_e\).For computing the part \(x_d x_\delta\) of \(g_2\) (up to sign) we have to extract (the signs of) 24 more entries of the vector \(v_1 \cdot g_2 y_e^{-1}\) and to solve another equation system as in the previous step. Here the relevant coordinates are stored at the
TAG_VECTOR
at offsetOFS_TAGS_X
, and the equation system is stored at offsetOFS_SOLVE_X
.To correct the sign in the part \(x_d x_\delta\), we have to extract another sign from \(v_1 \cdot g_2 \cdot y_e^{-1} (x_d x_\delta)^{-1}\) at the coordinate given by
OFS_TAGS_SIGN
.
Values:
-
enumerator OFS_NORM_A
Sum of the squares of the A part of \(v_1\) (mod 15)
-
enumerator OFS_DIAG_VA
For compatibly with older versions, always equal to 0
-
enumerator OFS_WATERMARK_PERM
Watermark of the A part of \(v_1\) (mod 15)
-
enumerator OFS_TAGS_Y
Entries of \(v_1\) used for computing \(y_e\)
-
enumerator OFS_SOLVE_Y
Equation system used for computing \(y_e\)
-
enumerator OFS_TAGS_X
Entries of \(v_1\) used for computing \(x_d\)
-
enumerator OFS_SOLVE_X
Equation system used for computing \(x_e\)
-
enumerator OFS_TAG_SIGN
Entry of \(v_1\) used for computing sign of \(x_d\)
Functions
-
int32_t mm_order_check_in_Gx0_fast(uint_mmv_t *v)
Quick check if a vector is an image under an element of \(G_{x0}\).
Assume that the vector \(v\) in \(\rho_{15}\) referred by
v
is the image of the precomputed order vector \(v_1\) under an (unknown) element \(g\) of the monster. The function checks if that element \(g\) is in the subgroup \(G_{x0}\) of the monster.The function may return 0, 1, or a negative value. If it returns 0 then \(g\) is not in \(G_{x0}\). If it returns 1 then \(g\) is in \(G_{x0}\) with an error probability that is negligible for all practial purposes. A negative return value indicates an error.
-
int32_t mm_order_check_in_Gx0(uint_mmv_t *v, uint32_t *g, uint32_t mode, uint_mmv_t *work)
Check if a vector is an image under an element of \(G_{x0}\).
Assume that the vector \(v\) in \(\rho_{15}\) referred by
v
is the image of the precomputed order vector \(v_1\) under an (unknown) element \(g\) of the monster. We want to find that element \(g\) if it is in the subgroup \(G_{x0}\) of the monster.We first describe the action of the function in the standard case that parameter
mode
is zero.The function computes the element \(g\) if it is in the subgroup \(G_{x0}\) of the monster; otherwise it fails.
In case of success the function writes the element \(g\) into the array
g
as a word in the generators of \(G_{x0}\) of length at most 11; and the function returns the length of that word.If no such element \(g_1\) has been found then the function returns a number greater than 256. Then the exact return value gives some indication why no such element \(g\) has been found; this is for debugging only.
A negative return value indicates an internal error.
The function also requires an array
work
of length 15468 as a work buffer. This is the capacity required for storing a vector in the representation \(\rho_{15}\).Parameter
mode
is a bit field that modifies the action of the function as follows:If bit 0 is set, then the inverse of the result \(g\) is returned in buffer
g
.If bit 1 is set then we insert an atom into the word in
g
that indicates the image of the vector \(\Omega \in \Lambda / 2 \Lambda\) under conjugation with \(g_0\). Such an atom is considered as a comment, acting as the neutral element of the monster group. This is required for functionmm_reduce_M
in filemm_reduce.c
. See documentation in that file for details.If bit 2 is set then we perform an action to be used for internal tests only. Then the function computes an element \(g_1\) such that \(g^{-1} g_1\in Q_{x0}\) holds in case \(g \in G_{x0}\). If \(g \notin G_{x0}\) then the function detects this fact with high probability. Usually, \(g_1\) is a shorter word in the generators of the monster than \(g\).
If bit 3 is set then input vector
v
is preserved; but the work bufferwork
must have the (doubled) length 30936 for storing an additional temporary copy of vectorv
.
-
int32_t mm_order_element_Gx0(uint32_t *g, uint32_t n, uint32_t *h, uint32_t o)
Compute exponent \(e\) such that \(g^e \in G_{x0}\).
Let \(g\) be the element of the monster group stored in the array
g
as a word of generators of the monster group of lengthn
.The function computes the smallest exponent \(e\) such that \(g^e\) is in \(G_{x0}\). Then the function writes \(h = g^e\) into the buffer
h
as a word of generators of \(G_{x0}\) of length at most 10. Let \(k\) be the length of the word representing \(h\). Then the function returns the value \(\mbox{0x100} \cdot e + k\); here we have \(1 \leq e \leq 119\) and \(0 \leq k \leq 10\).Computation of \(e\) is time consuming, and in some cases we are interested in small values of \(e\) only. Parameter
o
is an upper bound for the exponent \(e\) . The function may abort and return 0 in if \(e\) is greater thano
; then the data in bufferh
are invalid.A negative return value indicates an internal error.
-
int32_t mm_order_element_M(uint32_t *g, uint32_t n, uint32_t o)
Compute order of an element \(g\) of the monster.
Let \(g\) be the element of the monster group stored in the array
g
as a word of generators of the monster group of lengthn
.The function returns the order of \(g\).
Computation of the order is time consuming, and in some cases we are interested in small orders only. Parameter
o
is an upper bound for the order. The function may return 0 if the order is greater thano
.A negative return value indicates an error.
C interface for file mm_reduce.c
Function mm_reduce_M
is the most important C function in this project. It reduces an arbitrary element of the monster group (represented as a word in the generators of the monster) to a word of fixed maximum length. Function mm_reduce_M
uses the method in [Sey22] for reducing an element of the monster.
Here a word in the monster group is represented as an array of 32-bit integers of type uint32_t
as described in section The monster group in the API reference. Such an array represents a word of generators of the monster. Thus group multiplication is concatenation of words. An generator in a word (given by an entry in the array of integers) can be inverted by flipping its most significant bit.
According to [Sey22], and element \(g\) of the monster group can be computed from the images \(v^+ g\), \(v^- g\), and \(v_1 g\). Here \(v^+, v^- \in \rho_{15} \) are certain 2A axes, and \(v_1 \in \rho_{15}\) is certain vector used for recognizing an element of the subgroup \(G_{x0}\) of the monster, see ibid. for details. Representation \(\rho_{15}\) is the 198884-dimensional faithful representation of the monster group modulo 15. Vector \(v_1\) is also called an order vector; and we can use the functions in module mm_order.c
for dealing with a fixed precomputed order vector.
An element of \(\rho_{15}\) is implemented as a array of MM_OP15_LEN_V
integers of type uint_mmv_t
as described in The C interface of the mmgroup project, section Description of the mmgroup.mm extension. The value MM_OP15_LEN_V
is defined in file mm_op15.h
.
For reducing an element \(g\) of the monster we have to analyze the images \(v^+ g\), \(v^- g\), and \(v_1 g\) in that order. This file also exports subfunctions for performing these tasks. We use subfunctions mm_reduce_vector_vp
, mm_reduce_vector_vm
, and mm_reduce_vector_v1
for analyzing \(v^+ g\), \(v^- g\), and \(v_1 g\), respectively. These functions accumulate their results in a buffer (of type uint32_t[]
and size at least 128) that will eventually contain the reduced word equal to \(g\).
The following code example shows an implementation of the main function mm_reduce_M
based on these subfunctions, ignoring the error handling.
// The following buffers contain the element ``g`` to be reduced
uint32_t a[256]; // buffer containing element ``g``
uint32_t n; // length of data in buffer ``a``
// The folling buffers will contain the reduced element ``g``
uint32_t r[256]; // buffer for reduced element ``g``
uint32_t len; // length of data in buffer ``r``
// Temporary work buffers
uint_mmv_t v[MM_OP15_LEN_V]; // buffer for 2A axes
uint_mmv_twork[MM_OP15_LEN_V]; // work buffer
mm_op15_store_axis(V_PLUS, v ); // Store 2A axis V_PLUS in v
mm_op15_word(v, a, n, 1, work); // multiply v_plus with g
mm_reduce_vector_vp(0, v, mode, r, work); // reduce V_PLUS * g
mm_op15_store_axis(V_MINUS, v ); // Store 2A axis V_MINUS in v
mm_op15_word(v, a, n, 1, work); // multiply v_minus with g
mm_reduce_vector_vm(0,v, r, work); // reduce V_MINUS * g
mm_order_load_vector(v); // load the order vector v_1
mm_op15_word(v, a, n, 1, work); // multiply v_1 with g
len = mm_reduce_vector_v1(v, r, work); // reduce v_1 vector
// Now buffer ``r`` contains the reduced word of length ``len``
// equal to the element ``g`` of the monster group.
Functions
-
uint32_t mm_reduce_2A_axis_type(uint_mmv_t *v)
Return type of a 2A axis in rep of monster.
Let
v
be a vector in the 196884-dimensional representation of the monster group modulo15
, encoded as described in section Description of the mmgroup.mm<p> extensions in the description of the C interface.If
v
is a 2A axis then the function computes the type of the 2A axis. Each 2A axis corresponds uniquely to a 2A involution \(x\) in the monster. Let \(z\) be the central involution in the subgroup \(G_{x0}\) of the monster. Then the type of the 2A axisv
is the class of the product \(xz\) in the monster, which has one of the values 2A, 2B, 4A, 4B, 4C, 6A, 6C, 6F, 8B, 10A, 10B, 12CThe function returns a value
n * 2**28 + k * 2**24 + v
. Heren
is the number of the class, e.g.n == 6
for class 6C,k
encodes the letter in the name of the class (‘A’ = 1, ‘B’ = 2, …) e.g.k = 3
for class 6C.Output
v
is either 0 or a vector in the Leech lattice mod 2 found during the computation. Here a vector of type 2 is returned for classes 2A, 6A; and a vector of type 4 is returned for class 4A.Caution:
This is a quick disambiguation of the type of a 2A axis. The function may return any axis type if
v
is not a 2A axis.
-
int32_t mm_reduce_analyze_2A_axis(uint_mmv_t *v, uint32_t *r)
Analyze a 2A axis in rep of monster.
Let
v
be a vector in the 196884-dimensional representation of the monster group modulo15
, encoded as described in section Description of the mmgroup.mm<p> extensions in the description of the C interface.If
v
is a 2A axis then the function analyzes the type of the 2A axis. Each 2A axis corresponds uniquely to a 2A involution \(x\) in the monster. Let \(z\) be the central involution in the subgroup \(G_{x0}\) of the monster. Then the type of the 2A axisv
is the class of the product \(xz\) in the monster, which has one of the values 2A, 2B, 4A, 4B, 4C, 6A, 6C, 6F, 8B, 10A, 10B, 12CThe function returns 0 in case of success and a negative value value if it detects an error.
Buffer
r
should be at least 896 bytes long. It will contain the result.Details are yet to be documented!!!
Caution:
This is a quick analyis of a 2A axis. The function returns garbage if
v
is not a 2A axis.
-
uint32_t mm_reduce_find_type4(uint32_t *v, uint32_t n, uint32_t v2)
Select a type-4 vector from list of Leech lattice vectors
Let
v
be an array ofn
vectors in the Leech lattice modulo 2 in Leech lattice encoding.If parameter
v2
is 0 then the function returns the least vector of type 4 in the listv
with repect to a certain ordering. If listv
contains no vector of type 4 then the function returns 0.Here subtypes are ordered as follows:
[48, 40, (42, 44), 46, 43]
. So e.g. a vector of subtype40
is selected in favor of a vactor of subtype46
. We do not distinguish between substypes42
and44
. From all vectors of the same subtype (equalizing subtypes42
and44
) we return the smallest vector in the list in the natural order.If
v2
is nonzero then we accept only vectorsv1
in the listv
withtype(v1) = 4
andtype(v1 + v2) = 2
.The list
v
is destroyed. More precisely, all entries ofv
are masked with0xffffff
and subjected to an (undocumented) permutation.
-
int32_t mm_reduce_transform_v4(uint_mmv_t *v, uint32_t v4, uint32_t *target_axes, uint32_t *r, uint_mmv_t *work)
Transform a 2A axis to a ‘better’ 2A axis.
The function tries to transform the 2A axis \(v\) given by parameter
v
to a better axis. Therefore it first applies a transformation \(g \in G_{x0}\) given by parameterv4
. Herev4
must be a vector of type 4 in the Leech lattice mod 2 in Leech lattice encoding. Then \(g\) is the transformation mappingv4
to the standard type 4-vectorOmega
as computed by functiongen_leech2_reduce_type4
.In the next step this function tries to apply the transfomations \(\tau^e\) for \(e = 1,2\) (in that order) until the type of the axis \(v g \tau^e\) is in a set of types given by parameter
target_axes
. Heretarget_axes
must be an array of length 2 containing the feasible axis types, encoded as described in functionmm_reduce_2A_axis_type
. An unused entry in arraytarget_axes
should be set to0xffffffff
.If a suitable transformed axis \(v g \tau^e\) has been found then the function stores the element \(g \tau^e\) in the array referred by
r
; and it returns the length of the data in the arrayr
. Then it also overwrites the axis in bufferv
with the transformed axis.The function returns a negative value in case of any error, e.g. if no suitable transformed axis \(v\) has been found; then buffers
v
andr
will contain garbage.If the original axis \(v\) is orthogonal to the standard 2A axis then the transformed axis is also orthogonal to that axis.
Buffer
r
must have size at least 7. The function requires a work bufferwork
of the same type and size as parameterv
.
-
int32_t mm_reduce_load_axis(uint_mmv_t *v, uint32_t s)
Load the 2A axis \(v^+\) or \(v^-\) into a vector in \(\rho_{15}\).
The function loads the 2A axis \(v^+\) (in case
s == 0
) or \(v^-\) (in cases == 1
) in the vector referred byv
. Other values ofs
are illegal. Vectorv
will store an element of the representation \(\rho_{15}\) of the monster group as described in the header of this file. Vectors \(v^+\) and \(v^-\) are defined in [Sey22], Section 6.
-
int32_t mm_reduce_map_axis(uint32_t *vt, uint_mmv_t *v, uint32_t *a, uint32_t n, uint_mmv_t *work)
Transform a 2A axis with an element of the Monster group.
Here we encode a 2A axis \(v\) as follows. It may be encoded as an element of the group \(Q_{x0}\) in the integer referred by
vt
. In case*vt = 0
we encode \(v\) as a vector of the representation \(\rho_{15}\) of the Monster in the arrayv
. In case*vt != 0
the value*vt
must be a short element (corresponding to a type-2 vector in \(\Lambda/2\Lambda\)) of the group \(Q_{x0}\), in Leech lattice encoding.v
is ignored in case*vt != 0
.Let \(g\) be the element of the monster given as a word of generators in the buffer
a
of lengthn
. Then the function computes \(v' = v \cdot g\) and stores \(v'\) in*vt
(if possible), or inv
. In last case it sets*vt
to zero.The function returns 0 in case of success an a negative value in case of failure. It requires a work buffer
work
of the same type and size as parameterv
.
-
int32_t mm_reduce_vector_vp(uint32_t *vt, uint_mmv_t *v, uint32_t mode, uint32_t *r, uint_mmv_t *work)
Step 1 of the reduction of an element of the monster.
Here inputs
vt
andv
of this function encode a 2A axis \(v\) as described in functionmm_reduce_map_axis
. Here \(v\) is considered as an image \(v = v^+ \cdot g\) of \(v^+\) under the operation of an (unknown) element \(g\) of the Monster group.The function computes an element \(h\) of the monster group with \(v \cdot h = v^+\). We use the method in [Sey22], Section 6 ff. for computing \(h\).
The function stores \(h\) as a word of generators in the array
r
as described in the header of this file and returns the length of this word. That word is augmented by some atoms acting as commentsThe buffer referred by
r
should have length at least 128.Parameter
mode
is yet to be documented! In the current version is should be set to1
. This means that the function will strictly follow the reduction method in ibid.A negative return value indicates a fatal error.
Parameter
work
must refer to a work buffer of size at leastMM_OP15_LEN_V
.More details are yet to be documented!!!!
-
int32_t mm_reduce_vector_shortcut(uint32_t stage, uint32_t mode, uint32_t axis, uint32_t *r)
Simulate steps of the reduction of an element of the monster.
Yet to be documented!!!!
-
int32_t mm_reduce_vector_vm(uint32_t *vt, uint_mmv_t *v, uint32_t *r, uint_mmv_t *work)
Step 2 of the reduction of an element of the monster.
This function should be applied immediately after function
mm_reduce_vector_vp
.Here inputs
vt
andv
of this function encode a 2A axis \(v\) as described in functionmm_reduce_map_axis
. Here \(v\) is considered as an image \(v = v^+ \cdot g\) of \(v^+\) under the operation of an (unknown) element \(g\) of the Monster group.The function computes an element \(h\) of the monster group with \(v \cdot h = v^-\). We use the method in [Sey22], Section 8, for computing \(h\). Note that \(h\) preserves the 2A axis \(v^+\).
The function appends \(h\) as a word of generators to the array
r
as described in the header of this file and returns the length of the data in the arrayr
. That information in bufferr
is augmented by some atoms acting as comments.The buffer referred by
r
should have length at least 128.A negative return value indicates a fatal error.
Parameter
work
must refer to a work buffer of size at leastMM_OP15_LEN_V
.More details are yet to be documented!!!!
-
int32_t mm_reduce_vector_v1(uint_mmv_t *v, uint32_t *r, uint_mmv_t *work)
Step 3 of the reduction of an element of the monster.
This function should be applied immediately after functions
mm_reduce_vector_vp
andmm_reduce_vector_vm
.Here input
v
of this function must refer to the image of the precomputed order vector \(v_1 \in \rho_{15}\) under the operation of the same element \(g\) of the monster group as described in the documentation of functionmm_reduce_vector_vp
.The function computes an element \(h\) of the monster group with \(v \cdot h = v_1\). We use the method in [Sey22], Appendix A. for computing \(h\). Note that \(h\) preserves the 2A axes \(v^+\) and \(v^-\).
The function appends \(h\) as a word of generators to the array
r
as described in the header of this file and returns the length of the data in the arrayr
. That information in bufferr
is augmented by some atoms acting as comments.Finally, the function computes a word in the buffer that is equal to the element \(g\) of the monster group and stores that element in the buffer
r
. The function returns the length of data in bufferr
.The buffer referred by
r
should have length at least 128.A negative return value indicates a fatal error.
Parameter
work
must refer to a work buffer of size at leastMM_OP15_LEN_V
.
-
static inline int32_t mm_reduce_vector_v1_mod3(uint_mmv_t *v, uint32_t *r, uint_mmv_t *work)
Variant of Step 3 of the reduction of an element of the monster.
This is a variant of function
mm_reduce_vector_v1
that works with precomputed order vector \(v_1 \in \rho_{3}\) instead of an order vector in \(\rho_{15}\). Parameters and operation are the same as in functionmm_reduce_vector_v1
. But here inputv
of this function must refer to the image of the precomputed order vector \(v_1 \in \rho_{3}\) under the operation of the same element \(g\) of the monster group as described in the documentation of functionmm_reduce_vector_vp
.The order vector \(v_1 \in \rho_{3}\) can be obtained by using the functions in module
mm_vector_v1_mod3.c
.This function is faster than function
mm_reduce_vector_v1
. But the order vector in \(v_1 \in \rho_{3}\) may have a non-trivial centralizer in the Monster; so we cannot use it for checking equality of elements of the Monster.The buffer referred by
r
should have length at least 128.A negative return value indicates a fatal error.
Parameter
work
must refer to a work buffer of size at leastMM_OP3_LEN_V
.
-
static inline int32_t mm_reduce_vector_shorten(uint32_t *a, uint32_t n, uint32_t *r, uint_mmv_t *work)
Special case of Step 3 of reduction of an element of the monster.
This is a variant of function
mm_reduce_vector_v1
that works in the special case when all prefixes of a word \(g\) in the Monster map the 2A-involutions \(v^+\) and \(v^-\) to 2A-involutions in the subgroup \(Q_{x0}\) of \(G_{x0}\). Here the mapping is done via conjuation. That condition holds e.g if all prefixes of the word \(g\) are in \(\in N_x \cdot G_{x0}\).The function returns 0 in case of success and a negative value in case of failure. In case of success, this function is (at least) 100 times faster than function
mm_reduce_vector_v1
. So using this function leads to a substantial speedup when computing in the 2-local subgroups \(N_x\) or \(G_{x0}\) of the Monster. The user profits from this speedup without effort, since functionmm_reduce_M
calls functionmm_reduce_vector_shorten
when appropriate.Here the original element \(g\) of the Monster to be reduced must be stored in the buffer
a
of lengthn
as usual. Parametersr
andwork
are as in functionmm_reduce_vector_v1
.If function
mm_reduce_vector_shorten
returns a negative value then we may retry the final reduction of \(g\) with one of the functionsmm_reduce_vector_v1
ormm_reduce_vector_v1_mod3
.
-
int32_t mm_reduce_vector_incomplete(uint32_t *r)
Step finish incomplete reduction of an element of the monster.
This function should be applied immediately after function
mm_reduce_vector_vp
or after functionmm_reduce_vector_vn
.The function outputs the word already stored in the buffer
r
computed by the functionsmm_reduce_vector_vp
and, possibly,mm_reduce_vector_vn
and returns the length of the data in bufferr
. Here we assume that subsequent calls to the functions in the sequencemm_reduce_vector_vp, mm_reduce_vector_vn, mm_reduce_vector_v1
,that have not yet been called, would contribute nothing the the output assembled in buffer
r
.The buffer referred by
r
should have length at least 128.A negative return value indicates a fatal error.
More details are yet to be documented!!!!
-
int32_t mm_reduce_M(uint32_t *a, uint32_t n, uint32_t mode, uint32_t *r)
Reduce an element in the monster group.
This is the most important function in the project. It reduces an arbitrary element \(g\) of the monster to an element \(h\). The value of the element \(h\) depends on the value of \(g\) as an element of the monster group, but not of the representation of \(g\).
Let \(g\) be the element of the monster given as a word of generators in the buffer
a
of lengthn
. Then the function computes the reduced element \(h\) of the monster with \(g = h\). We use the method in [Sey22] for computing \(h\).The function stores \(h\) as a word of generators in the array
r
as described in the header of this file and returns the length of this word.A negative return value indicates a fatal error.
The buffer referred by
r
should have length at least 128.Parameter
mode
should usually be set to zero. It is interpreted as follows:If bit 0 of
mode
is set then the reduction is strictly compatible with the reduction process described in [Sey22]. Otherwise we perform a more practical reduction. The latter reduction ensures e.g. that an element of the subgroup \(G_{x0}\) is always represented as a word in the generators of that subgroup. This feature greatly accelerates computations in the subgroup \(G_{x0}\).Bit 1 of
mode
should be set for tests only. If this bit is set then we omit some simplifications of the input prior to the actual reduction.
-
uint32_t mm_reduce_set_order_vector_mod15(uint32_t mode)
Set a special reduction mode for tests.
The end user need not call this function.
In [Sey22] we show how to compute an ‘order vector’ \(v_1\) in the representation \(\rho_{15}\) of the Monster satisfying the following property:
The only element of the Monster fixing \(v_1\) is the neutral element of the Monster.
For verifying this property of \(v_1\) is suffices to use the methods in [LPWW98]. Thus by tracing the an image of \(v_1\) under an element \(g\) back to its preimage \(v_1\) we obtain a verification of a reduction process which depends on classical results only.
By default, the main reduction function
mm_reduce_M
in this module uses an ‘order vector’ in \(\rho_3\) which leads to a faster reduction process than obtained by using \(v_1\).When calling function
mm_reduce_set_order_vector_mod15
with parametermode = 1
then in all subsequent calls to functionmm_reduce_M
we will use an ‘order vector’ \(v_1\) in \(\rho_{15}\) as desrcibed above; and we will verify that the ‘reduced’ form of an element \(g\) of the Monster maps \(v_1\) to the same vector as the original element \(g\) does.This gives a tester the capability to do long calcuations in the Monster group that will be verified by using classical results without referring to the theory developed in [Sey22].
The user may switch back to the default behaviour by calling function
mm_reduce_set_order_vector_mod15
with parametermode = 0
. The function returns the value of parametermode
passed in the previous call (or the default value 0 at first call).
C interface for file mm_shorten.c
This file contains function for reducing a word of generators of the Monster group. Here word reduction is done by computations in the subgroups \(G_{x0} = 2^{1+24}.\mbox{Co}_1\) and \(N_0 = 2^{2+11+22}.(\mbox{Mat}_{24} \times \mbox{Sym}_3)\). To some extent, we will also compute in the Frobenius group of order 21 generated by the generators \(\tau\) and \(\xi\) of the Monster.
Internally, we store a word a
of generators of the Monster in a structure of type gt_word_type
. Here the word a
is split into subwords, where each subword is in the double coset \(G_{x0} N_0\). Such a subword is represented as a word of generators of \(G_{x0}\), followed by a power of the triality element \(\xi\). A subword is stored in a structure of type gt_subword_type
.
Unless otherwise stated, a negative return value of a function is this module indicates an error.
Structures required for this module are defined in file mm_reduce.h
.
The following code block demonstrates the reduction of a word with the functions in this module (ignoring error handling).
// Assume that the following buffer contains a word ``g``
// of length 10 of generators of the Monster group
#define INPUT_LENGTH 10
uint32_t in_buf[INPUT_LENGTH];
// Declare a sufficiently long output buffer
#define MAX_OUTPUT_LENGTH 20
uint32_t out_buf[MAX_OUTPUT_LENGTH];
// Define a reduction mode as specified in function gt_word_alloc
#define REDUCTION_MODE 1
// Allocate a structure for reduction
gt_word_type* p_gt = gt_word_alloc(REDUCTION_MODE, NULL, 0);
// Enter the word ``g`` into that structure
gt_word_append(p_gt, in_buf, INPUT_LENGTH);
// Reduce the word in that structure
gt_word_reduce(p_gt);
// Store the reduced word in the output buffer and the actual
// length of that word in variable output_length
int32_t output_length;
output_length = gt_word_store(p_gt, out_buf, MAX_OUTPUT_LENGTH);
// Free the allocated structure
gt_word_free(p_gt);
Functions
-
void gt_subword_clear(gt_subword_type *p_gtsub)
Low-level function.
Set a subword to the empty subword.
-
gt_word_type *gt_word_alloc(uint32_t mode, void *p_buffer, size_t nbytes)
Create a structure of type
gt_word_type
This function creates a valid structure of type
gt_word_type
and returns a pointer to that structure. The returned structure contains the empty word of generators of the Monster. If a bufferp_buffer
ofnbytes
bytes length is given as a parameter then the structure may be ininitalized inside this buffer. We recommendnbytes >= 4096
.If
p_buffer = NULL
ornbytes
is too small then a buffer is allocated via the C functionmalloc
. You should always use the returned pointer as a pointer to a valid structure of typegt_word_type
containing the neutral element of the Monster.The structure referred by returned pointer will contain the circular doubly linked list with a single entry of type
gt_subword_type
. This entry is an end-of-file mark. So the whole word stored in that structure corresponds to the neutral element of the Monster group.In any case function
gt_word_free
must be called to free all buffers allocated by this function and, possibly, by other function in this module applied to the pointer returned by this function.Parameter
mode
specifies the reduction mode:mode = 0
means no reduction. Here the user has to apply the low-level functions in this module to perform reduction. This mode is used for testing.mode = 1
means the maximum possible reduction which is supported.mode = 2
means a lazy mode of reduction. The idea is to reduce only in cases where we can expect a substantial decrease of the word length. This mode is faster thanmode = 1
.This function returns
NULL
in case of failure, e.g. if the C functionmalloc
`fails to allocate memory.
-
void gt_word_free(gt_word_type *p_gt)
Free a structure of type
gt_word_type
This function frees the memory allocated to a structure of type
gt_word_type
created by functiongt_word_alloc
. Ultimately, it must be applied to all pointers created by functiongt_word_alloc
in order to avoid memory leaks. It is safe to apply functiongt_word_free
to theNULL
pointer.
-
void gt_word_clear(gt_word_type *p_gt)
Set content of the structure
*p_gt
to the empty word.This function sets the value of the structure of type
gt_word_type
referred byp_gt
to the neutral element of the Monster. It also frees all allocated memory blocks referred byp_gt
, except for the blockp_gt
itself.
-
int32_t gt_word_insert(gt_word_type *p_gt)
Low-level function.
Insert an empty subword after the current subword pf
*p_gt
and set the position of the current subword to the new subword.Return a negative value if out of memory.
-
int32_t gt_word_delete(gt_word_type *p_gt)
Low-level function.
Delete the current subword, and set the position of the current subword to its predecessor.
Return a negative value on an attempt to delete an EOF mark.
-
int32_t gt_word_seek(gt_word_type *p_gt, int32_t pos, uint32_t set)
Low-level function.
Move the pointer to the current subword to position ‘pos’ Her pos = 0 means the EOF mark if ‘set’ is True, and the position of the current subword otherwise. pos = i+1 means the subword after pos = i, pos = i-1 means node subword pos = i.
It is an error to move p_gt->p_node across the EOF node. When starting at the EOF node we may move forward or back until finding the EOF node once again, but not any further.
-
int32_t gt_word_append_sub_part(gt_word_type *p_gt, uint32_t *a, uint32_t n)
Low-level function.
Try to append a prefix of word ‘a’ of length ‘n’ to the current subword. Return number of atoms of ‘a’ sucessfully appended to that word. A negative return value inducates an error.
-
int32_t gt_word_reduce_sub(gt_word_type *p_gt, uint32_t sub_mode)
Low-level function.
Reduce current subword
sub_mode = 0: lazy reduction (just some word shortening)
sub_mode = 1: standard reduction
sub_mode = 2: as sub_mode 0, but move also prefix in N_x0 to previous subword
sub_mode = 3: as sub_mode 1, but move also prefix in N_x0 to previous subword
-
int32_t gt_word_rule_join(gt_word_type *p_gt)
Low-level reduction function.
Try to join current subwort
p_gt->p_node
with its predecessor. Return 1 and letp_gt->p_node
point to first node being changed if the rule could be applied. Return 0 and do not changep_gt->p_node
this is not the case. Return a negative number in case of a fatal error.
-
int32_t gt_word_rule_t_xi_t(gt_word_type *p_gt)
Low-level reduction function.
This function tries to apply a reduction rule:
\(\tau^{e_1} \xi^{e_2} \tau^{e_3} \rightarrow \xi^{e_4} \tau^{e_5} \xi^{e_6}\).
Such a rule exists for all \(0 < e_1, e_2, e_3 < 3\). This rule is applied to the subword
p_gt->p_node
and to its predecessor. Applying such a rule decreases the number of generators \(\tau^{\pm 1}\) in a word.The function returns 1 and lets
p_gt->p_node
point to first node being changed if such rule could be applied. It returns 0 and does not changep_gt->p_node
this is not the case. It returns a negative number in case of a fatal error.To show the existence of suitable reduction rules as mentioned above we put \(a = \tau \xi^{-1}\). Then we verify that \(a\) has order 7 and that \(\tau^{-1} a \tau = a^2\) holds. Therefore is suffices to verify that the group operations corresponding to these relations fix the ‘order vector’ in the representation \(\rho_{15}\) .
Since \(\tau\) has order 3, the group generated by \(\tau\) and \(a\) (and hence also the group generated by \(\tau\) and \(\xi\)) is visibly a Frobenius group of order 21. Finding suitable reduction rules in such a group is easy.
-
int32_t gt_word_append(gt_word_type *p_gt, uint32_t *a, uint32_t n)
Append word of generators to strcture
*p_gt
Append the word
a
of lengthn
to the word in the buffer refered byp_gt
.A negative return value inducates an error.
At exit, pointer
p_gt->p_node
will point to theEOF
mark.
-
uint32_t gt_word_n_subwords(uint32_t *a, uint32_t n)
Return number of subwords required to store element of the Monster.
Return (an upper bound for) the number of subwords in a doubly linked list of type
gt_word_type
required to store the word of generators of the Monster of lengthn
referred bya
.
-
int32_t gt_word_length(gt_word_type *p_gt)
Return the length of the word stored in
*p_gt
.
-
int32_t gt_word_reduce(gt_word_type *p_gt)
Reduce the word stored in
*p_gt
.The function reduces the word \(g\) stored in the structure
*p_gt
. The mode of reduction depends on the parametermode
passed to functiongt_word_alloc
when creating that structure. The function returns:0 if \(g\) is not known to be in any subgroup of the Monster
4 if \(g\) is known to be in \(G_{x0} \cdot N_0\)
5 if \(g\) is known to be in \(N_0\)
6 if \(g\) is known to be in \(G_{x0}\)
7 if \(g\) is known to be in \(N_{x0} = G_{x0} \cap N_0\)
A negative value in case of failure.
If the return value is > 0 (i.e. if we know \(g \in G_{x0} \cdot N_0\)) then we also have performed a full reduction of the result.
-
int32_t gt_word_store(gt_word_type *p_gt, uint32_t *pa, uint32_t maxlen)
Store the word in
*p_gt
in an array.The function stores the word in
*p_gt
in the arraya
(of lengthmaxlen
) referred bypa
. It returns the actual lengthn
of the word stored in the arraya
.The function returns a negative value in case of failure, e.g. if
n > maxlen
.
-
int32_t gt_word_to_mm_compress(gt_word_type *p_gt, mm_compress_type *p_c)
Compress word in
*p_gt
to strcuture of typemm_compress_type
Yet to be tested and documented!!!
-
int32_t gt_word_compress(gt_word_type *p_gt, uint64_t *p_n)
Compress word in
*p_gt
to a 256-bit integer``.Yet to be tested and documented!!!
-
int32_t gt_word_shorten(uint32_t *g, uint32_t n, uint32_t *g1, uint32_t n1max, uint32_t mode)
Reduce a word of generators of the Monster group.
Let \(g\) be the word of the monster group of length
n
stored in the arrayg
. The function reduces the word \(g\) and stores the reduced word in the bufferg1
of lengthn1max
. It returns the actual lengthn1
of the reduced word.Internally, the function uses a buffer of type
gt_word_type
for reduction. Parametermode
controls the reduction mode; it is specified as in functiongt_word_alloc
.The function returns a negative value in case of failure, e.g. if
n1 > n1max
.
C interface for file mm_compress.c
This file contains functions for compressing a word of generators of the Monster group to an integer.
TODO: Documentation yet missing!
Functions
-
void mm_compress_pc_init(mm_compress_type *pc, uint32_t back)
yet to be documented
-
int32_t mm_compress_pc_add_nx(mm_compress_type *pc, uint32_t *m, uint32_t len)
yet to be documented
-
int32_t mm_compress_pc_add_type2(mm_compress_type *pc, uint32_t c)
yet to be documented
-
int32_t mm_compress_pc_add_type4(mm_compress_type *pc, uint32_t c)
yet to be documented
-
int32_t mm_compress_pc_add_t(mm_compress_type *pc, uint32_t t)
yet to be documented
-
int32_t mm_compress_pc(mm_compress_type *pc, uint64_t *p_n)
yet to be documented
-
int32_t mm_compress_pc_expand_int(uint64_t *p_n, uint32_t *m)
yet to be documented
C interface for file mm_vector_v1_mod3.c
File mm_vector_v1_mod3
contains a precomuted vector v1_mod3
of the representation of the monster group (mod 3). This vector can be used for obtaining an (unknown) element \(g\) of the subgroup \(G_{x0}\) of the monster from and image of that vector under \(g\).
So the functions in this module are similar to those in module mm_order.c
, but faster.
Note that we cannot check membership in \(G_{x0}\) with the functions in this module!
This module is yet a stub!!!
Functions
-
void mm_order_load_vector_v1_mod3(uint_mmv_t *p_dest)
Load order vector from tables to a buffer.
The function stores the precomputed vector
v1_mod3
into the array referred byp_dest
. That array must must be sufficiently long to store a vector of the representation \(\rho_{3}\).
-
int32_t mm_order_compare_v1_mod3(uint_mmv_t *v)
Compare vector with precomputed order vector.
The function compares the vector \(v\) in the representation \(\rho_{3}\) of the monster group referred by
v
with \(v_1\) , where \(v_1\) is the precomute vectorv1_mod3
.The function returns 0 in case of equality and 1 otherwise. It destroys the vector in the buffer
v
.
-
int32_t mm_order_find_Gx0_via_v1_mod3(uint_mmv_t *v, uint32_t *g)
Find an element \(g\) of the subgroup \(G_{x0}\).
Yet to be documented!!!