/**************************************************************************** ** ** This file is part of GAP, a system for computational discrete algebra. ** ** Copyright of GAP belongs to its developers, whose names are too numerous ** to list here. Please refer to the COPYRIGHT file for details. ** ** SPDX-License-Identifier: GPL-2.0-or-later
*/
/**************************************************************************** ** ** *H There is a representations of GFQ vectors with entries packed into ** bytes, called IsVec8BitRep, which inherits from IsDataObjectRep ** The 1st 4 bytes stores the actual vector length (in field elements) ** as a C integer. The 2nd component stores the field size as a C integer ** The data bytes begin at the 3rd component. ** ** In addition, this file defines format and access for the fieldinfo ** objects which contain the meat-axe tables for the arithmetics. ** ** There is a special representation for matrices, all of whose rows ** are immutable packed GFQ vectors over the same q, which is a positional ** representation Is8BitMatrixRep. Some special methods for such matrices ** are included here. **
*/
/**************************************************************************** ** *V FieldInfo8Bit . . . . . . . . . . .plain list (length 256) of field info ** ** This list caches the field info used for the fast arithmetic
*/
static Obj TypeMat8Bit(UInt q, UInt mut)
{
UInt col = mut ? 1 : 2;
Obj type; #ifdef HPCGAP
type = ELM0_LIST(ELM0_LIST(TYPES_MAT8BIT, col), q); #else
type = ELM_PLIST(ELM_PLIST(TYPES_MAT8BIT, col), q); #endif if (type == 0) return CALL_2ARGS(TYPE_MAT8BIT, INTOBJ_INT(q), mut ? True : False); else return type;
}
/**************************************************************************** ** *V TYPE_FIELDINFO_8BIT ** ** A type of data object with essentially no GAP visible semantics at all **
*/
/**************************************************************************** ** *V GetFieldInfo( <q> ) . .make or recover the meataxe table for a field ** always call this, as the tables are lost by ** save/restore. It's very cheap if the table already ** exists **
*/
staticvoid MakeFieldInfo8Bit(UInt q)
{
FF gfq; // the field
UInt p; // characteristic
UInt d; // degree
UInt i, j, k, l; // loop variables
UInt e; // number of elements per byte
UInt pows[7]; // table of powers of q for packing and unpacking bytes
Obj info; // The table being constructed
FFV mult; // multiplier for scalar product
FFV prod; // used in scalar product
UInt val; // used to build up some answers
UInt val0;
UInt elt, el1, el2; // used to build up some answers const FFV * succ;
p = (UInt)PbyQ[q];
d = (UInt)DbyQ[q];
gfq = FiniteField(p, d);
e = 0; for (i = 1; i <= 256; i *= q)
pows[e++] = i;
pows[e] = i; // simplifies things to have one more
e--;
GAP_ASSERT(e <= 5);
info = NewWordSizedBag(T_DATOBJ, sizeof(struct FieldInfo8Bit));
SetTypeDatObj(info, TYPE_FIELDINFO_8BIT);
succ = SUCC_FF(gfq);
// from here to the end, no garbage collections should happen
FieldInfo8BitPtr fi = FIELDINFO_8BIT(info);
fi->q = q;
fi->p = p;
fi->d = d;
fi->e = e;
// conversion tables FFV to/from our numbering // we assume that 0 and 1 are always the zero and one // of the field. In char 2, we assume that xor corresponds // to addition, otherwise, the order doesn't matter
UInt1 * convtab = fi->FELT_FFE; if (p != 2) for (i = 0; i < q; i++)
convtab[i] = (UInt1)i; else for (i = 0; i < q; i++)
convtab[i] = Char2Lookup[d][i];
// simply invert the permutation to get the other one for (i = 0; i < q; i++) {
j = convtab[i];
fi->FFE_FELT[j] = NEW_FFE(gfq, i);
}
// Now we need to store the position in Elements(GF(q)) of each field // element for the sake of NumberFFVector // // The rules for < between finite field elements make this a bit // complex for non-prime fields
// deal with zero and one
fi->GAPSEQ[0] = INTOBJ_INT(0);
fi->GAPSEQ[fi->FELT_FFE[1]] = INTOBJ_INT(1);
if (q != 2) { if (d == 1) for (i = 2; i < q; i++)
fi->GAPSEQ[i] = INTOBJ_INT(i); else { // run through subfields, filling in entry for all the new // elements of each field in turn
UInt q1 = 1;
UInt pos = 2; for (i = 1; i <= d; i++) {
q1 *= p; if (d % i == 0) { for (j = 2; j < q1; j++) {
UInt place =
fi->FELT_FFE[1 + (j - 1) * (q - 1) / (q1 - 1)]; if (fi->GAPSEQ[place] == 0) {
fi->GAPSEQ[place] = INTOBJ_INT(pos);
pos++;
}
}
}
}
}
}
// entry setting table SETELT...[(i*e+j)*256 +k] is the result // of overwriting the jth element with i in the byte k for (i = 0; i < q; i++) for (j = 0; j < e; j++) { Int iej_cache = (i * e + j) * 256; for (k = 0; k < 256; k++)
fi->SETELT[iej_cache + k] =
(UInt1)((k / pows[j + 1]) * pows[j + 1] + i * pows[j] +
(k % pows[j]));
}
// entry access GETELT...[i*256+j] recovers the ith entry from the // byte j for (i = 0; i < e; i++) for (j = 0; j < 256; j++)
fi->GETELT[i * 256 + j] = (UInt1)(j / pows[i]) % q;
// scalar * vector multiply SCALAR...[i*256+j] is the scalar // product of the byte j with the felt i for (i = 0; i < q; i++) {
mult = VAL_FFE(FFE_FELT_FIELDINFO_8BIT(info, i)); for (j = 0; j < 256; j++) {
val = 0; for (k = 0; k < e; k++) {
elt = VAL_FFE(
FFE_FELT_FIELDINFO_8BIT(info, fi->GETELT[k * 256 + j]));
prod = PROD_FFV(elt, mult, succ);
val += pows[k] * FELT_FFE_FIELDINFO_8BIT(info)[prod];
}
fi->SCALAR[i * 256 + j] = val;
}
}
// inner product INNER...[i+256*j] is a byte whose LS entry is the // contribution to the inner product of bytes i and j for (i = 0; i < 256; i++) for (j = i; j < 256; j++) {
val = 0; for (k = 0; k < e; k++) {
el1 = VAL_FFE(
FFE_FELT_FIELDINFO_8BIT(info, fi->GETELT[k * 256 + i]));
el2 = VAL_FFE(
FFE_FELT_FIELDINFO_8BIT(info, fi->GETELT[k * 256 + j]));
elt = PROD_FFV(el1, el2, succ);
val = SUM_FFV(val, elt, succ);
}
val = fi->SETELT[256 * e * FELT_FFE_FIELDINFO_8BIT(info)[val]];
fi->INNER[i + 256 * j] = val;
fi->INNER[j + 256 * i] = val;
}
// PMULL and PMULU are the lower and upper bytes of the product // of single-byte polynomials for (i = 0; i < 256; i++) for (j = i; j < 256; j++) {
val0 = 0; for (k = 0; k < e; k++) {
val = 0; for (l = 0; l <= k; l++) {
el1 = VAL_FFE(FFE_FELT_FIELDINFO_8BIT(
info, fi->GETELT[l * 256 + i]));
el2 = VAL_FFE(FFE_FELT_FIELDINFO_8BIT(
info, fi->GETELT[(k - l) * 256 + j]));
elt = PROD_FFV(el1, el2, succ);
val = SUM_FFV(val, elt, succ);
}
val0 += pows[k] * FELT_FFE_FIELDINFO_8BIT(info)[val];
}
fi->PMULL[i + 256 * j] = val0;
fi->PMULL[j + 256 * i] = val0;
// if there is just one entry per byte then we don't need the // upper half if (ELS_BYTE_FIELDINFO_8BIT(info) > 1) {
val0 = 0; for (k = e; k < 2 * e - 1; k++) {
val = 0; for (l = k - e + 1; l < e; l++) {
el1 = VAL_FFE(FFE_FELT_FIELDINFO_8BIT(
info, fi->GETELT[l * 256 + i]));
el2 = VAL_FFE(FFE_FELT_FIELDINFO_8BIT(
info, fi->GETELT[(k - l) * 256 + j]));
elt = PROD_FFV(el1, el2, succ);
val = SUM_FFV(val, elt, succ);
}
val0 += pows[k - e] * FELT_FFE_FIELDINFO_8BIT(info)[val];
}
fi->PMULU[i + 256 * j] = val0;
fi->PMULU[j + 256 * i] = val0;
}
}
// In odd characteristic, we need the addition table // ADD...[i*256+j] is the vector sum of bytes i and j if (p != 2) { for (i = 0; i < 256; i++) for (j = i; j < 256; j++) {
val = 0; for (k = 0; k < e; k++) {
el1 = VAL_FFE(FFE_FELT_FIELDINFO_8BIT(
info, fi->GETELT[k * 256 + i]));
el2 = VAL_FFE(FFE_FELT_FIELDINFO_8BIT(
info, fi->GETELT[k * 256 + j]));
val += pows[k] * FELT_FFE_FIELDINFO_8BIT(
info)[SUM_FFV(el1, el2, succ)];
}
fi->ADD[i + 256 * j] = val;
fi->ADD[j + 256 * i] = val;
}
}
#ifdef HPCGAP
MakeBagReadOnly(info); #endif // remember the result #ifdef HPCGAP
ATOMIC_SET_ELM_PLIST_ONCE(FieldInfo8Bit, q, info); #else
SET_ELM_PLIST(FieldInfo8Bit, q, info); #endif
CHANGED_BAG(FieldInfo8Bit);
}
Obj GetFieldInfo8Bit(UInt q)
{
Obj info;
GAP_ASSERT(2 < q && q <= 256); #ifdef HPCGAP
info = ATOMIC_ELM_PLIST(FieldInfo8Bit, q); if (info == 0) {
MakeFieldInfo8Bit(q);
info = ATOMIC_ELM_PLIST(FieldInfo8Bit, q);
} #else
info = ELM_PLIST(FieldInfo8Bit, q); if (info == 0) {
MakeFieldInfo8Bit(q);
info = ELM_PLIST(FieldInfo8Bit, q);
} #endif return info;
}
/**************************************************************************** ** *F RewriteVec8Bit( <vec>, <q> ) . . . . . . . . . . rewrite <vec> over GF(q) ** ** <vec> should be an 8 bit vector over a smaller field of the same ** characteristic
*/
if (q < q1) {
ErrorMayQuit("Cannot convert a vector compressed over GF(%d) to " "small field GF(%d)",
q1, q);
}
if (((q - 1) % (q1 - 1)) != 0) {
ErrorMayQuit( "Cannot convert a vector compressed over GF(%d) to GF(%d)", q1,
q);
}
if (DoFilter(IsLockedRepresentationVector, vec) == True) {
ErrorMayQuit("Cannot convert a locked vector compressed over " "GF(%d) to GF(%d)",
q1, q);
}
// extract the required info
len = LEN_VEC8BIT(vec);
info = GetFieldInfo8Bit(q);
info1 = GetFieldInfo8Bit(q1);
GAP_ASSERT(P_FIELDINFO_8BIT(info) == P_FIELDINFO_8BIT(info1));
GAP_ASSERT(!(D_FIELDINFO_8BIT(info) % D_FIELDINFO_8BIT(info1)));
els = ELS_BYTE_FIELDINFO_8BIT(info);
els1 = ELS_BYTE_FIELDINFO_8BIT(info1);
if (len == 0) {
SET_FIELD_VEC8BIT(vec, q); return;
}
// enlarge the bag
ResizeWordSizedBag(vec, SIZE_VEC8BIT(len, els));
mult = (q - 1) / (q1 - 1); while (i >= 0) {
val = VAL_FFE(convtab1[gettab1[byte1 + 256 * (i % els1)]]); if (val != 0)
val = 1 + (val - 1) * mult;
byte = settab[byte + 256 * (i % els + els * convtab[val])]; if (0 == i % els) {
*ptr-- = byte;
byte = 0;
} if (0 == i % els1)
byte1 = *--ptr1;
i--;
}
SET_FIELD_VEC8BIT(vec, q);
}
/**************************************************************************** ** *F RewriteGF2Vec( <vec>, <q> ) . . . . . . . . . . rewrite <vec> over GF(q) ** ** <vec> should be a GF2 vector and q a larger power of 2 ** ** This function uses the interface in vecgf2.h
*/
if (DoFilter(IsLockedRepresentationVector, vec) == True) {
ErrorMayQuit("Cannot convert a locked vector compressed over " "GF(2) to GF(%d)",
q, 0);
}
// extract the required info
len = LEN_GF2VEC(vec);
info = GetFieldInfo8Bit(q);
els = ELS_BYTE_FIELDINFO_8BIT(info);
// enlarge the bag
ResizeWordSizedBag(vec, SIZE_VEC8BIT(len, els));
settab = SETELT_FIELDINFO_8BIT(info);
convtab = FELT_FFE_FIELDINFO_8BIT(info);
zero = convtab[0];
one = convtab[1];
ptr1 = CONST_BLOCKS_GF2VEC(vec) + NUMBER_BLOCKS_GF2VEC(vec) - 1;
block = *ptr1;
ptr = BYTES_VEC8BIT(vec) + (len - 1) / els;
byte = 0;
i = len - 1;
while (i >= 0) {
byte = settab[byte +
256 * (i % els + els * ((block & MASK_POS_GF2VEC(i + 1))
? one
: zero))]; if (0 == i % els) {
*ptr-- = byte;
byte = 0;
} if (0 == i % BIPEB)
block = *--ptr1;
i--;
}
SET_FIELD_VEC8BIT(vec, q);
SET_LEN_VEC8BIT(vec, len);
type = TypeVec8Bit(q, mut);
SET_TYPE_POSOBJ(vec, type);
}
/**************************************************************************** ** *F ConvVec8Bit( <list>, <q> ) . . . convert a list into 8bit vector object
*/
staticvoid ConvVec8Bit(Obj list, UInt q)
{ Int len; // logical length of the vector Int i; // loop variable
UInt p; // char
UInt d; // degree
FF f; // field
Obj info; // field info object
UInt elts; // elements per byte const UInt1 * settab; // element setting table const UInt1 * convtab; // FFE -> FELT conversion table
Obj firstthree[3]; // the first three entries may get clobbered my the // early bytes
UInt e; // loop variable
UInt1 byte; // byte under construction
UInt1 * ptr; // place to put byte
Obj elt;
UInt val;
UInt nsize;
Obj type;
if (q > 256)
ErrorQuit("Field size %d is too much for 8 bits", q, 0); if (q == 2)
ErrorQuit("GF2 has its own representation", 0, 0);
// already in the correct representation if (IS_VEC8BIT_REP(list)) {
UInt q1 = FIELD_VEC8BIT(list); if (q1 == q) return; elseif (q1 < q && ((q - 1) % (q1 - 1)) == 0) {
RewriteVec8Bit(list, q); return;
} // remaining case is list is written over too large a field // pass through to the generic code
} elseif (IS_GF2VEC_REP(list)) {
RewriteGF2Vec(list, q); return;
}
len = LEN_LIST(list);
// OK, so now we know which field we want, set up data
info = GetFieldInfo8Bit(q);
p = P_FIELDINFO_8BIT(info);
d = D_FIELDINFO_8BIT(info);
f = FiniteField(p, d);
elts = ELS_BYTE_FIELDINFO_8BIT(info);
// We may need to resize first, as small lists get BIGGER // in this process
nsize = SIZE_VEC8BIT(len, elts); if (nsize > SIZE_OBJ(list))
ResizeWordSizedBag(list, nsize);
// writing the first byte may clobber the third list entry // before we have read it, so we take a copy
firstthree[0] = ELM0_LIST(list, 1);
firstthree[1] = ELM0_LIST(list, 2);
firstthree[2] = ELM0_LIST(list, 3);
// main loop -- e is the element within byte
e = 0;
byte = 0;
ptr = BYTES_VEC8BIT(list); for (i = 1; i <= len; i++) {
elt = (i <= 3) ? firstthree[i - 1] : ELM_LIST(list, i);
GAP_ASSERT(CHAR_FF(FLD_FFE(elt)) == p);
GAP_ASSERT(d % DegreeFFE(elt) == 0);
val = VAL_FFE(elt); if (val != 0 && FLD_FFE(elt) != f) {
val = 1 + (val - 1) * (q - 1) / (SIZE_FF(FLD_FFE(elt)) - 1);
} // Must get these afresh after every list access, just in case this is // a virtual list whose accesses might cause a garbage collection
settab = SETELT_FIELDINFO_8BIT(info);
convtab = FELT_FFE_FIELDINFO_8BIT(info);
byte = settab[(e + elts * convtab[val]) * 256 + byte]; if (++e == elts || i == len) {
*ptr++ = byte;
byte = 0;
e = 0;
}
}
// it can happen that the few bytes after the end of the data are // not zero, because they had data in them in the old version of the list // In most cases this doesn't matter, but in characteristic 2, we must // clear up to the end of the word, so that AddCoeffs behaves correctly. // // SL -- lets do this in all characteristics, it can never hurt
while ((ptr - BYTES_VEC8BIT(list)) % sizeof(UInt))
*ptr++ = 0;
// retype and resize bag if (nsize != SIZE_OBJ(list))
ResizeWordSizedBag(list, nsize);
SET_LEN_VEC8BIT(list, len);
SET_FIELD_VEC8BIT(list, q);
type = TypeVec8Bit(q, IS_MUTABLE_OBJ(list));
SetTypeDatObj(list, type);
RetypeBag(list, T_DATOBJ);
}
static UInt LcmDegree(UInt d, UInt d1)
{
UInt x, y, g;
x = d;
y = d1; while (x != 0 && y != 0) { if (x <= y)
y = y % x; else
x = x % y;
} if (x == 0)
g = y; else
g = x; return (d * d1) / g;
}
/**************************************************************************** ** *F NewVec8Bit( <list>, <q> ) . . . convert a list into 8bit vector object ** ** This is a non-destructive counterpart of ConvVec8Bit
*/
static Obj NewVec8Bit(Obj list, UInt q)
{ Int len; // logical length of the vector Int i; // loop variable
UInt p; // char
UInt d; // degree
FF f; // field
Obj info; // field info object
UInt elts; // elements per byte const UInt1 * settab; // element setting table const UInt1 * convtab; // FFE -> FELT conversion table
UInt e; // loop variable
UInt1 byte; // byte under construction
UInt1 * ptr; // place to put byte
Obj elt;
UInt val;
UInt nsize;
Obj type;
Obj res; // resulting 8bit vector object
if (q > 256)
ErrorQuit("Field size %d is too much for 8 bits", q, 0); if (q == 2)
ErrorQuit("GF2 has its own representation", 0, 0);
// already in the correct representation if (IS_VEC8BIT_REP(list)) {
UInt q1 = FIELD_VEC8BIT(list); if (q1 == q) {
res = CopyVec8Bit(list, 1); if (!IS_MUTABLE_OBJ(list)) // index 0 is for immutable vectors
SetTypeDatObj(res, TypeVec8Bit(q, 0)); return res;
} elseif (q1 < q && ((q - 1) % (q1 - 1)) == 0) { // rewriting to a larger field
res = CopyVec8Bit(list, 1);
RewriteVec8Bit(res, q); // TODO: rework RewriteVec8Bit and avoid calling CopyVec8Bit if (!IS_MUTABLE_OBJ(list))
SetTypeDatObj(res, TypeVec8Bit(q, 0)); return res;
} // remaining case is list is written over too large a field // pass through to the generic code
} elseif (IS_GF2VEC_REP(list)) {
res = ShallowCopyVecGF2(list);
RewriteGF2Vec(res, q); // TODO: rework RewriteGF2Vec and avoid calling ShallowCopyVecGF2 if (!IS_MUTABLE_OBJ(list))
SetTypeDatObj(res, TypeVec8Bit(q, 0)); return res;
}
// OK, so now we know which field we want, set up data
info = GetFieldInfo8Bit(q);
p = P_FIELDINFO_8BIT(info);
d = D_FIELDINFO_8BIT(info);
f = FiniteField(p, d);
// determine the size and create a new bag
len = LEN_LIST(list);
elts = ELS_BYTE_FIELDINFO_8BIT(info);
nsize = SIZE_VEC8BIT(len, elts);
res = NewWordSizedBag(T_DATOBJ, nsize);
// main loop -- e is the element within byte
e = 0;
byte = 0;
ptr = BYTES_VEC8BIT(res); for (i = 1; i <= len; i++) {
elt = ELM_LIST(list, i);
GAP_ASSERT(CHAR_FF(FLD_FFE(elt)) == p);
GAP_ASSERT(d % DegreeFFE(elt) == 0);
val = VAL_FFE(elt); if (val != 0 && FLD_FFE(elt) != f) {
val = 1 + (val - 1) * (q - 1) / (SIZE_FF(FLD_FFE(elt)) - 1);
} // Must get these afresh after every list access, just in case this is // a virtual list whose accesses might cause a garbage collection
settab = SETELT_FIELDINFO_8BIT(info);
convtab = FELT_FFE_FIELDINFO_8BIT(info);
byte = settab[(e + elts * convtab[val]) * 256 + byte]; if (++e == elts || i == len) {
*ptr++ = byte;
byte = 0;
e = 0;
}
}
// retype bag
SET_LEN_VEC8BIT(res, len);
SET_FIELD_VEC8BIT(res, q);
type = TypeVec8Bit(q, IS_MUTABLE_OBJ(list));
SetTypeDatObj(res, type);
return res;
}
/**************************************************************************** ** *F FuncCOPY_VEC8BIT( <self>, <list> ) . . . . . convert into 8bit vector rep ** ** This is a non-destructive counterpart of FuncCOPY_GF2VEC
*/ static Obj FuncCOPY_VEC8BIT(Obj self, Obj list, Obj q)
{
UInt iq = GetPositiveSmallInt(SELF_NAME, q); return NewVec8Bit(list, iq);
}
/**************************************************************************** ** *F PlainVec8Bit( <list> ) . . . convert an 8bit vector into an ordinary list ** ** 'PlainVec8Bit' converts the vector <list> to a plain list.
*/
// resize the list and retype it, in this order if (True == DoFilter(IsLockedRepresentationVector, list)) {
ErrorMayQuit( "Attempt to convert locked compressed vector to plain list", 0,
0);
}
len = LEN_VEC8BIT(list);
q = FIELD_VEC8BIT(list);
info = GetFieldInfo8Bit(q);
elts = ELS_BYTE_FIELDINFO_8BIT(info);
if (len != 0) {
gettab = GETELT_FIELDINFO_8BIT(info); // keep the first two entries // because setting the third destroys them
first = FFE_FELT_FIELDINFO_8BIT(info,
gettab[CONST_BYTES_VEC8BIT(list)[0]]); if (len > 1)
second = FFE_FELT_FIELDINFO_8BIT(
info, gettab[256 * (1 % elts) +
CONST_BYTES_VEC8BIT(list)[1 / elts]]);
// replace the bits by FF elts as the case may be // this must of course be done from the end of the list backwards for (i = len; 2 < i; i--) {
fieldobj = FFE_FELT_FIELDINFO_8BIT(
info, gettab[256 * ((i - 1) % elts) +
CONST_BYTES_VEC8BIT(list)[(i - 1) / elts]]);
SET_ELM_PLIST(list, i, fieldobj);
} if (len > 1)
SET_ELM_PLIST(list, 2, second);
SET_ELM_PLIST(list, 1, first);
} // Null out any entries after the end of valid data // As the size of the VEC8BIT might not evenly divide sizeof(Int), we // cannot use PLIST methods to set the end of the list to zero
startblank = (Char *)(PTR_BAG(list) + (len + 1));
endblank = (Char *)PTR_BAG(list) + SIZE_BAG(list);
memset(startblank, 0, endblank - startblank);
CHANGED_BAG(list);
}
/**************************************************************************** ** *F FuncPLAIN_VEC8BIT( <self>, <list> ) . . . . convert back into plain list
*/ static Obj FuncPLAIN_VEC8BIT(Obj self, Obj list)
{ if (!IS_VEC8BIT_REP(list)) {
RequireArgument(SELF_NAME, list, "must be an 8bit vector");
} if (DoFilter(IsLockedRepresentationVector, list) == True) {
ErrorMayQuit("Cannot convert a locked vector compressed over " "GF(%d) to a plain list",
FIELD_VEC8BIT(list), 0);
}
PlainVec8Bit(list);
/**************************************************************************** ** *F AddVec8BitVec8BitInner( <sum>, <vl>, <vr>, <start>, <stop> ) ** ** This is the real vector add routine. Others are all calls to this ** one. ** Addition is done from THE BLOCK containing <start> to the one ** containing <stop> INCLUSIVE. The remainder of <sum> is unchanged. ** <sum> may be the same vector as <vl> or ** <vr>. <vl> and <vr> must be over the same field and <sum> must be ** initialized as a vector over this field of length at least <stop>. **
*/
// Maybe there's nothing to do if (!stop) return;
info = GetFieldInfo8Bit(FIELD_VEC8BIT(sum));
GAP_ASSERT(Q_FIELDINFO_8BIT(info) == FIELD_VEC8BIT(vl));
GAP_ASSERT(Q_FIELDINFO_8BIT(info) == FIELD_VEC8BIT(vr));
GAP_ASSERT(LEN_VEC8BIT(sum) >= stop);
GAP_ASSERT(LEN_VEC8BIT(vl) >= stop);
GAP_ASSERT(LEN_VEC8BIT(vr) >= stop);
p = P_FIELDINFO_8BIT(info);
elts = ELS_BYTE_FIELDINFO_8BIT(info); // Convert from 1 based to zero based addressing
start--;
stop--; if (p == 2) { const UInt * ptrL2; const UInt * ptrR2;
UInt * ptrS2;
UInt * endS2; // HPCGAP: Make sure to only check read guards for vl & vr.
ptrL2 = CONST_BLOCKS_VEC8BIT(vl) + start / (sizeof(UInt) * elts);
ptrR2 = CONST_BLOCKS_VEC8BIT(vr) + start / (sizeof(UInt) * elts);
ptrS2 = BLOCKS_VEC8BIT(sum) + start / (sizeof(UInt) * elts);
endS2 = BLOCKS_VEC8BIT(sum) + stop / (sizeof(UInt) * elts) + 1; if (sum == vl) { while (ptrS2 < endS2) {
*ptrS2 ^= *ptrR2;
ptrS2++;
ptrR2++;
}
} elseif (sum == vr) { while (ptrS2 < endS2) {
*ptrS2 ^= *ptrL2;
ptrL2++;
ptrS2++;
}
} else while (ptrS2 < endS2)
*ptrS2++ = *ptrL2++ ^ *ptrR2++;
} else { const UInt1 * ptrL; const UInt1 * ptrR;
UInt1 * ptrS;
UInt1 * endS;
UInt x; const UInt1 * addtab = ADD_FIELDINFO_8BIT(info); // HPCGAP: Make sure to only check read guards for vl & vr.
ptrL = CONST_BYTES_VEC8BIT(vl) + start / elts;
ptrR = CONST_BYTES_VEC8BIT(vr) + start / elts;
ptrS = BYTES_VEC8BIT(sum) + start / elts;
endS = BYTES_VEC8BIT(sum) + stop / elts + 1; if (vl == sum) { while (ptrS < endS) {
x = *ptrR; if (x != 0)
*ptrS = addtab[256 * (*ptrS) + x];
ptrR++;
ptrS++;
}
} elseif (vr == sum) { while (ptrS < endS) {
x = *ptrL; if (x != 0)
*ptrS = addtab[256 * (x) + *ptrS];
ptrS++;
ptrL++;
}
} else while (ptrS < endS)
*ptrS++ = addtab[256 * (*ptrL++) + *ptrR++];
}
}
/**************************************************************************** ** *F SumVec8BitVec8Bit( <vl>, <vr> ) ** ** This is perhaps the simplest wrapper for the Add..Inner function ** it allocates a new vector for the result, and adds the whole vectors into ** it. No checking is done. The result follows the new mutability convention ** (mutable if either argument is).
*/
q = FIELD_VEC8BIT(vl);
len = LEN_VEC8BIT(vl);
info = GetFieldInfo8Bit(q);
elts = ELS_BYTE_FIELDINFO_8BIT(info);
sum = NewWordSizedBag(T_DATOBJ, SIZE_VEC8BIT(len, elts));
SET_LEN_VEC8BIT(sum, len);
type = TypeVec8Bit(q, IS_MUTABLE_OBJ(vl) || IS_MUTABLE_OBJ(vr));
SetTypeDatObj(sum, type);
SET_FIELD_VEC8BIT(sum, q);
CHANGED_BAG(sum);
AddVec8BitVec8BitInner(sum, vl, vr, 1, len); return sum;
}
/**************************************************************************** ** *F FuncSUM_VEC8BIT_VEC8BIT( <self>, <vl>, <vr> ) ** ** This is the GAP callable method for +. The method installation should ** ensure that we have matching characteristics, but we may not have a common ** field or the same lengths **
*/
static Obj ConvertToVectorRep; // BH: changed to static
/**************************************************************************** ** *F MultVec8BitFFEInner( <prod>, <vec>, <scal>, <start>, <stop> ) ** ** This is the real vector * scalar routine. Others are all calls to this ** one. ** Multiplication is done from THE BLOCK containing <start> to the one ** containing <stop> INCLUSIVE. The remainder of <prod> is unchanged. ** <prod> may be the same vector as <vec> ** <scal> must be written over the field of <vec> and ** <prod> must be ** initialized as a vector over this field of length at least <stop>. **
*/
/**************************************************************************** ** *F MultVec8BitFFE( <vec>, <scal> ) . . . simple scalar multiply ** ** This is a basic wrapper for Mult...Inner. It allocates space for ** the result, promotes the scalar to the proper field if necessary and ** runs over the whole vector **
*/
/**************************************************************************** ** *F FuncPROD_VEC8BIT_FFE( <self>, <vec>, <ffe> ) ** ** This is the GAP callable method for *. The method installation should ** ensure that we have matching characteristics, but we may not have a common ** field **
*/
/**************************************************************************** ** *F FuncPROD_FFE_VEC8BIT( <self>, <ffe>, <vec> ) ** ** This is the GAP callable method for *. The method installation should ** ensure that we have matching characteristics, but we may not have a common ** field ** ** Here we can fall back on the method above.
*/
/**************************************************************************** ** *F AddVec8BitVec8BitMultInner( <sum>, <vl>, <vr>, <mult> <start>, <stop> ) ** ** This is the real vector add multiple routine. Others are all calls to ** this one. It adds <mult>*<vr> to <vl> leaving the result in <sum> ** ** Addition is done from THE BLOCK containing <start> to the one ** containing <stop> INCLUSIVE. The remainder of <sum> is unchanged. ** <sum> may be the same vector as <vl> or ** <vr>. <vl> and <vr> must be over the same field and <sum> must be ** initialized as a vector over this field of length at least <stop>. ** ** <mult> is assumed to be over the correct field and may not be zero **
*/
// Now check the field of <mul> if (q != SIZE_FF(FLD_FFE(mul))) {
Obj info;
UInt d, d1;
FFV val;
info = GetFieldInfo8Bit(q);
d = D_FIELDINFO_8BIT(info);
d1 = DegreeFFE(mul); if (d % d1) return TRY_NEXT_METHOD;
val = VAL_FFE(mul); if (val != 0)
val = 1 + (val - 1) * (q - 1) / (SIZE_FF(FLD_FFE(mul)) - 1);
mul = NEW_FFE(FiniteField(P_FIELDINFO_8BIT(info), d), val);
}
MultVec8BitFFEInner(vec, vec, mul, 1, LEN_VEC8BIT(vec)); return (Obj)0;
}
/**************************************************************************** ** *F FuncADD_ROWVECTOR_VEC8BITS_5( <self>, <vl>, <vr>, <mul>, <from>, <to> ) ** ** The three argument method for AddRowVector **
*/
static Obj AddRowVector;
static Obj FuncADD_ROWVECTOR_VEC8BITS_5(
Obj self, Obj vl, Obj vr, Obj mul, Obj from, Obj to)
{
UInt q;
UInt len;
len = LEN_VEC8BIT(vl); // There may be nothing to do if (LT(to, from)) return (Obj)0;
if (len != LEN_VEC8BIT(vr)) {
ErrorMayQuit("AddRowVector: <left> and <right> must be " "vectors of the same length",
0, 0);
} if (LT(INTOBJ_INT(len), to)) {
ErrorMayQuit("AddRowVector: <to> (%d) is greater than the " "length of the vectors (%d)",
INT_INTOBJ(to), len);
} if (LT(to, from)) return (Obj)0;
// Now we know that the characteristics must match, but not the fields
q = FIELD_VEC8BIT(vl);
// fix up fields if necessary if (q != FIELD_VEC8BIT(vr) || q != SIZE_FF(FLD_FFE(mul))) {
Obj info, info1;
UInt d, d1, q1, d2, d0, q0, p, i;
FFV val;
// find a common field
info = GetFieldInfo8Bit(q);
d = D_FIELDINFO_8BIT(info);
q1 = FIELD_VEC8BIT(vr);
info1 = GetFieldInfo8Bit(q1);
d1 = D_FIELDINFO_8BIT(info1);
d2 = DegreeFFE(mul);
d0 = LcmDegree(d, d1);
d0 = LcmDegree(d0, d2);
p = P_FIELDINFO_8BIT(info);
GAP_ASSERT(p == P_FIELDINFO_8BIT(info1));
GAP_ASSERT(p == CHAR_FF(FLD_FFE(mul)));
q0 = 1; for (i = 0; i < d0; i++)
q0 *= p;
// if the exponent is bigger than 31, overflow changes the value to 0 if (d0 > 8 || q0 > 256) return TRY_NEXT_METHOD; if ((q0 > q && DoFilter(IsLockedRepresentationVector, vl) == True) ||
(q0 > q1 && DoFilter(IsLockedRepresentationVector, vr) == True)) return TRY_NEXT_METHOD;
RewriteVec8Bit(vl, q0);
RewriteVec8Bit(vr, q0);
val = VAL_FFE(mul); if (val != 0)
val = 1 + (val - 1) * (q0 - 1) / (SIZE_FF(FLD_FFE(mul)) - 1);
mul = NEW_FFE(FiniteField(p, d0), val);
}
/**************************************************************************** ** *F FuncADD_ROWVECTOR_VEC8BITS_3( <self>, <vl>, <vr>, <mul> ) ** ** The three argument method for AddRowVector **
*/
static Obj FuncADD_ROWVECTOR_VEC8BITS_3(Obj self, Obj vl, Obj vr, Obj mul)
{
UInt q; if (LEN_VEC8BIT(vl) != LEN_VEC8BIT(vr)) {
ErrorMayQuit( "SUM: <left> and <right> must be vectors of the same length", 0,
0);
} // Now we know that the characteristics must match, but not the fields
q = FIELD_VEC8BIT(vl);
// fix up fields if necessary if (q != FIELD_VEC8BIT(vr) || q != SIZE_FF(FLD_FFE(mul))) {
Obj info, info1;
UInt d, d1, q1, d2, d0, q0, p, i;
FFV val; // find a common field
info = GetFieldInfo8Bit(q);
d = D_FIELDINFO_8BIT(info);
q1 = FIELD_VEC8BIT(vr);
info1 = GetFieldInfo8Bit(q1);
d1 = D_FIELDINFO_8BIT(info1);
d2 = DegreeFFE(mul);
d0 = LcmDegree(d, d1);
d0 = LcmDegree(d0, d2);
p = P_FIELDINFO_8BIT(info);
GAP_ASSERT(p == P_FIELDINFO_8BIT(info1));
GAP_ASSERT(p == CHAR_FF(FLD_FFE(mul)));
q0 = 1; for (i = 0; i < d0; i++)
q0 *= p;
// if the exponent is bigger than 31, overflow changes the value to 0 if (d0 > 8 || q0 > 256) return TRY_NEXT_METHOD; if ((q0 > q &&
CALL_1ARGS(IsLockedRepresentationVector, vl) == True) ||
(q0 > q1 && CALL_1ARGS(IsLockedRepresentationVector, vr) == True)) return TRY_NEXT_METHOD;
RewriteVec8Bit(vl, q0);
RewriteVec8Bit(vr, q0);
val = VAL_FFE(mul); if (val != 0)
val = 1 + (val - 1) * (q0 - 1) / (SIZE_FF(FLD_FFE(mul)) - 1);
mul = NEW_FFE(FiniteField(p, d0), val);
}
AddVec8BitVec8BitMultInner(vl, vl, vr, mul, 1, LEN_VEC8BIT(vl)); return (Obj)0;
}
/**************************************************************************** ** *F FuncADD_ROWVECTOR_VEC8BITS_2( <self>, <vl>, <vr>) ** ** The two argument method for AddRowVector **
*/
static Obj FuncADD_ROWVECTOR_VEC8BITS_2(Obj self, Obj vl, Obj vr)
{
UInt q; if (LEN_VEC8BIT(vl) != LEN_VEC8BIT(vr)) {
ErrorMayQuit( "SUM: <left> and <right> must be vectors of the same length", 0,
0);
} // Now we know that the characteristics must match, but not the fields
q = FIELD_VEC8BIT(vl); // fix up fields if necessary if (q != FIELD_VEC8BIT(vr)) {
Obj info1;
Obj info;
UInt d, d1, q1, d0, q0, p, i; // find a common field
info = GetFieldInfo8Bit(q);
d = D_FIELDINFO_8BIT(info);
q1 = FIELD_VEC8BIT(vr);
info1 = GetFieldInfo8Bit(q1);
d1 = D_FIELDINFO_8BIT(info1);
d0 = LcmDegree(d, d1);
p = P_FIELDINFO_8BIT(info);
GAP_ASSERT(p == P_FIELDINFO_8BIT(info1));
q0 = 1; for (i = 0; i < d0; i++)
q0 *= p;
// if the exponent is bigger than 31, overflow changes the value to 0 if (d0 > 8 || q0 > 256) return TRY_NEXT_METHOD; if ((q0 > q &&
CALL_1ARGS(IsLockedRepresentationVector, vl) == True) ||
(q0 > q1 && CALL_1ARGS(IsLockedRepresentationVector, vr) == True)) return TRY_NEXT_METHOD;
RewriteVec8Bit(vl, q0);
RewriteVec8Bit(vr, q0);
q = q0;
}
AddVec8BitVec8BitInner(vl, vl, vr, 1, LEN_VEC8BIT(vl)); return (Obj)0;
}
/**************************************************************************** ** *F SumVec8BitVec8BitMult( <vl>, <vr>, <mult> ) ** ** This is perhaps the simplest wrapper for the Add..MultInner function ** it allocates a new vector for the result, and adds the whole vectors into ** it. Mult is promoted to the proper field if necessary. ** The result follows the new mutability convention ** (mutable if either argument is).
*/
if (FIELD_VEC8BIT(vl) != FIELD_VEC8BIT(vr)) {
UInt ql = FIELD_VEC8BIT(vl), qr = FIELD_VEC8BIT(vr);
Obj infol = GetFieldInfo8Bit(ql), infor = GetFieldInfo8Bit(qr);
UInt newd =
LcmDegree(D_FIELDINFO_8BIT(infol), D_FIELDINFO_8BIT(infor));
UInt p, newq;
UInt i;
p = P_FIELDINFO_8BIT(infol);
GAP_ASSERT(p == P_FIELDINFO_8BIT(infor));
newq = 1; for (i = 0; i < newd; i++)
newq *= p; // if the exponent is bigger than 31, overflow changes the value to 0 if (newd > 8 || newq > 256 ||
(ql != newq && True == CALL_1ARGS(IsLockedRepresentationVector, vl)) ||
(qr != newq && True == CALL_1ARGS(IsLockedRepresentationVector, vr))) {
diff = DiffListList(vl, vr);
CALL_1ARGS(ConvertToVectorRep, diff); return diff;
} else {
RewriteVec8Bit(vl, newq);
RewriteVec8Bit(vr, newq);
}
}
// Finally the main line return DiffVec8BitVec8Bit(vl, vr);
}
/**************************************************************************** ** *F CmpVec8BitVec8Bit( <vl>, <vr> ) .. comparison, returns -1, 0 or 1 ** ** characteristic and field should have been checked outside, but we must ** deal with length variations
*/
// we stop a little short, so as to handle the final byte separately
endL = ptrL + lenl / elts;
endR = ptrR + lenr / elts;
gettab = GETELT_FIELDINFO_8BIT(info);
ffe_elt = CONST_FFE_FELT_FIELDINFO_8BIT(info); while (ptrL < endL && ptrR < endR) { if (*ptrL == *ptrR) {
ptrL++;
ptrR++;
} else { for (e = 0; e < elts; e++) {
vall = gettab[*ptrL + 256 * e];
valr = gettab[*ptrR + 256 * e]; if (vall != valr) { if (LT(ffe_elt[vall], ffe_elt[valr])) return -1; else return 1;
}
}
ErrorQuit("panic: bytes differed but all entries the same", 0, 0);
}
} // now the final byte if (lenl < lenr)
len = lenl; else
len = lenr;
// look first at the shared part for (e = 0; e < (len % elts); e++) {
vall = gettab[*ptrL + 256 * e];
valr = gettab[*ptrR + 256 * e]; if (vall != valr) { if (LT(ffe_elt[vall], ffe_elt[valr])) return -1; else return 1;
}
} // if that didn't decide then the longer list is bigger if (lenr > lenl) return -1; elseif (lenr == lenl) return 0; else return 1;
}
/**************************************************************************** ** *F ScalarProductVec8Bits( <vl>, <vr> ) scalar product of vectors ** ** Assumes that length and field match **
*/
/**************************************************************************** ** *F UInt DistanceVec8Bits( <vl>, <vr> ) Hamming distance ** ** Assumes that length and field match **
*/
/**************************************************************************** ** *F DistDistrib8Bits( <veclis>, <ovec>, <d>, <osum>, <pos>, <l>, <m>) **
*/ staticvoid DistDistrib8Bits(
Obj veclis, // pointers to matrix vectors and their multiples
Obj vec, // vector we compute distance to
Obj d, // distances list
Obj sum, // position of the sum vector
UInt pos, // recursion depth
UInt l // length of basis
)
{
UInt i;
UInt di;
Obj cnt;
Obj vp;
Obj one;
Obj tmp;
UInt len;
UInt q;
vp = ELM_PLIST(veclis, pos);
one = INTOBJ_INT(1);
len = LEN_VEC8BIT(sum);
q = FIELD_VEC8BIT(sum); for (i = 0; i < q; i++) { if (pos < l) {
DistDistrib8Bits(veclis, vec, d, sum, pos + 1, l);
} else {
di = DistanceVec8Bits(sum, vec);
cnt = ELM_PLIST(d, di + 1); if (IS_INTOBJ(cnt) && SUM_INTOBJS(tmp, cnt, one)) {
cnt = tmp;
SET_ELM_PLIST(d, di + 1, cnt);
} else {
cnt = SumInt(cnt, one);
SET_ELM_PLIST(d, di + 1, cnt);
CHANGED_BAG(d);
}
}
AddVec8BitVec8BitInner(sum, sum, ELM_PLIST(vp, i + 1), 1, len);
}
TakeInterrupt();
}
static Obj FuncDISTANCE_DISTRIB_VEC8BITS(
Obj self,
Obj veclis, // pointers to matrix vectors and their multiples
Obj vec, // vector we compute distance to
Obj d) // distances list
{
Obj sum; // sum vector
UInt len;
UInt q;
len = LEN_VEC8BIT(vec);
q = FIELD_VEC8BIT(vec);
// get space for sum vector and zero out
sum = ZeroVec8Bit(q, len, 0); // do the recursive work
DistDistrib8Bits(veclis, vec, d, sum, 1, LEN_PLIST(veclis));
static UInt
AClosVec8Bit(Obj veclis, // pointers to matrix vectors and their multiples
Obj vec, // vector we compute distance to
Obj sum, // position of the sum vector
UInt pos, // recursion depth
UInt l, // length of basis
UInt cnt, // number of vectors used already
UInt stop, // stop value
UInt bd, // best distance so far
Obj bv, // best vector so far
Obj coords,
Obj bcoords)
{
UInt i, j;
UInt di;
Obj vp;
UInt q;
UInt len;
// This is the case where we do not add any multiple of // the current basis vector if (pos + cnt < l) {
bd = AClosVec8Bit(veclis, vec, sum, pos + 1, l, cnt, stop, bd, bv,
coords, bcoords); if (bd <= stop) { return bd;
}
}
q = FIELD_VEC8BIT(vec);
len = LEN_VEC8BIT(vec);
vp = ELM_PLIST(veclis, pos);
// we need to add each scalar multiple and recurse for (i = 1; i < q; i++) {
AddVec8BitVec8BitInner(sum, sum, ELM_PLIST(vp, i), 1, len); if (coords)
SET_ELM_PLIST(coords, pos, INTOBJ_INT(i)); if (cnt == 0) { // do we have a new best case
di = DistanceVec8Bits(sum, vec); if (di < bd) {
bd = di;
OverwriteVec8Bit(bv, sum); if (coords) for (j = 1; j <= l; j++) {
Obj x;
x = ELM_PLIST(coords, j);
SET_ELM_PLIST(bcoords, j, x);
} if (bd <= stop) return bd;
}
} elseif (pos < l) {
bd = AClosVec8Bit(veclis, vec, sum, pos + 1, l, cnt - 1, stop, bd,
bv, coords, bcoords); if (bd <= stop) { return bd;
}
}
} // reset component
AddVec8BitVec8BitInner(sum, sum, ELM_PLIST(vp, q), 1, len); if (coords)
SET_ELM_PLIST(coords, pos, INTOBJ_INT(0));
sum = ZeroVec8Bit(q, len, 1);
best = ZeroVec8Bit(q, len, 1);
// do the recursive work
AClosVec8Bit(veclis, vec, sum, 1, LEN_PLIST(veclis), INT_INTOBJ(cnt),
INT_INTOBJ(stop), len + 1, // maximal value +1
best, (Obj)0, (Obj)0);
sum = ZeroVec8Bit(q, len, 1);
best = ZeroVec8Bit(q, len, 1);
len2 = LEN_PLIST(veclis);
coords = NEW_PLIST(T_PLIST_CYC, len2);
bcoords = NEW_PLIST(T_PLIST_CYC, len2);
SET_LEN_PLIST(coords, len2);
SET_LEN_PLIST(bcoords, len2); for (i = 1; i <= len2; i++) {
SET_ELM_PLIST(coords, i, INTOBJ_INT(0));
SET_ELM_PLIST(bcoords, i, INTOBJ_INT(0));
}
// do the recursive work
AClosVec8Bit(veclis, vec, sum, 1, LEN_PLIST(veclis), INT_INTOBJ(cnt),
INT_INTOBJ(stop), len + 1, // maximal value +1
best, coords, bcoords);
info = GetFieldInfo8Bit(FIELD_VEC8BIT(vec));
elts = ELS_BYTE_FIELDINFO_8BIT(info);
gettab = GETELT_FIELDINFO_8BIT(info);
convtab = GAPSEQ_FELT_FIELDINFO_8BIT(info);
ptrS = CONST_BYTES_VEC8BIT(vec);
len = LEN_VEC8BIT(vec);
res = INTOBJ_INT(0);
f = INTOBJ_INT(FIELD_VEC8BIT(vec)); // Field size as GAP integer
if (len == 0) return INTOBJ_INT(1);
for (i = 0; i < len; i++) {
elt = convtab[gettab[ptrS[i / elts] + 256 * (i % elts)]];
res = ProdInt(res, f); // ``shift''
res = SumInt(res, elt); if (!IS_INTOBJ(res)) { // a garbage collection might have moved the pointers
gettab = GETELT_FIELDINFO_8BIT(info);
convtab = GAPSEQ_FELT_FIELDINFO_8BIT(info);
ptrS = CONST_BYTES_VEC8BIT(vec);
}
}
return res;
}
/**************************************************************************** ** *F FuncCOSET_LEADERS_INNER_8BITS( <self>, <veclis>, <weight>, <tofind>, ** <leaders> ) ** ** Search for new coset leaders of weight <weight>
*/
/**************************************************************************** ** *F FuncQ_VEC8BIT( <self>, <list> ) . . . . . . . . size of the field
*/ static Obj FuncQ_VEC8BIT(Obj self, Obj list)
{ return INTOBJ_INT(FIELD_VEC8BIT(list));
}
/**************************************************************************** ** *F FuncELM0_VEC8BIT( <self>, <list>, <pos> ) . select elm of an 8bit vector ** ** 'ELM0_VEC8BIT' returns the element at the position <pos> of the 8bit ** vector <list>, or `Fail' if <list> has no assigned object at <pos>. It ** is the responsibility of the caller to ensure that <pos> is a positive ** integer.
*/
/**************************************************************************** ** *F FuncELM_VEC8BIT( <self>, <list>, <pos> ) . . select elm of an 8bit vector ** ** 'ELM_VEC8BIT' returns the element at the position <pos> of the 8bit ** vector <list>. An error is signalled if <pos> is not bound. It is the ** responsibility of the caller to ensure that <pos> is a positive integer.
*/ static Obj FuncELM_VEC8BIT(Obj self, Obj list, Obj pos)
{
UInt p;
Obj info;
UInt elts;
p = GetPositiveSmallInt(SELF_NAME, pos); if (LEN_VEC8BIT(list) < p) {
ErrorMayQuit("List Element: <list>[%d] must have an assigned value",
p, 0);
} else {
info = GetFieldInfo8Bit(FIELD_VEC8BIT(list));
elts = ELS_BYTE_FIELDINFO_8BIT(info); return FFE_FELT_FIELDINFO_8BIT(
info, GETELT_FIELDINFO_8BIT(
info)[CONST_BYTES_VEC8BIT(list)[(p - 1) / elts] +
256 * ((p - 1) % elts)]);
}
}
/**************************************************************************** ** *F FuncELMS_VEC8BIT( <self>, <list>, <poss> ) . select elms of 8 bit vector ** ** The results are returned in the compressed format
*/ static Obj FuncELMS_VEC8BIT(Obj self, Obj list, Obj poss)
{
UInt p;
Obj pos;
Obj info;
UInt elts;
UInt len;
Obj res;
UInt i;
UInt elt; const UInt1 * gettab; const UInt1 * settab; const UInt1 * ptrS;
UInt1 * ptrD;
UInt e;
UInt1 byte;
UInt len2;
len = LEN_PLIST(poss);
info = GetFieldInfo8Bit(FIELD_VEC8BIT(list));
len2 = LEN_VEC8BIT(list);
elts = ELS_BYTE_FIELDINFO_8BIT(info);
res = NewWordSizedBag(T_DATOBJ, SIZE_VEC8BIT(len, elts));
SetTypeDatObj(res, TYPE_DATOBJ(list));
SET_FIELD_VEC8BIT(res, FIELD_VEC8BIT(list));
SET_LEN_VEC8BIT(res, len);
gettab = GETELT_FIELDINFO_8BIT(info);
settab = SETELT_FIELDINFO_8BIT(info);
ptrS = CONST_BYTES_VEC8BIT(list);
ptrD = BYTES_VEC8BIT(res);
e = 0;
byte = 0; for (i = 1; i <= len; i++) {
pos = ELM_PLIST(poss, i); if (!IS_POS_INTOBJ(pos))
ErrorQuit("ELMS_VEC8BIT: positions list includes a %s, should " "all be positive small integers",
(Int)TNAM_OBJ(pos), 0);
p = INT_INTOBJ(pos); if (p > len2)
ErrorQuit("ELMS_VEC8BIT: positions list includes index %d in a " "list of length %d",
(Int)p, (Int)len2);
elt = gettab[ptrS[(p - 1) / elts] + 256 * ((p - 1) % elts)];
byte = settab[byte + 256 * (e + elts * elt)];
e++; if (e == elts) {
*ptrD++ = byte;
e = 0;
byte = 0;
}
} if (e)
*ptrD = byte;
return res;
}
/**************************************************************************** ** *F FuncELMS_VEC8BIT_RANGE( <self>, <list>, <range> ) . ** select elms of an 8 bit vector ** ** The results are returned in the compressed format
*/ static Obj FuncELMS_VEC8BIT_RANGE(Obj self, Obj list, Obj range)
{
UInt p;
Obj info;
UInt elts;
UInt len;
UInt lenl;
UInt low; Int inc;
Obj res;
UInt i;
UInt elt; const UInt1 * gettab; const UInt1 * settab; const UInt1 * ptrS;
UInt1 * ptrD;
UInt e;
UInt1 byte;
info = GetFieldInfo8Bit(FIELD_VEC8BIT(list));
elts = ELS_BYTE_FIELDINFO_8BIT(info);
len = GET_LEN_RANGE(range);
low = GET_LOW_RANGE(range);
inc = GET_INC_RANGE(range);
lenl = LEN_VEC8BIT(list); if (inc < 0) { if (low > lenl || low + inc * (len - 1) < 1)
ErrorQuit("ELMS_VEC8BIT_RANGE: Range includes indices which are " "too high or too low",
0, 0);
} elseif (low < 1 || low + inc * (len - 1) > lenl)
ErrorQuit("ELMS_VEC8BIT_RANGE: Range includes indices which are too " "high or too low",
0, 0);
res = NewWordSizedBag(T_DATOBJ, SIZE_VEC8BIT(len, elts));
SetTypeDatObj(res, TYPE_DATOBJ(list));
SET_FIELD_VEC8BIT(res, FIELD_VEC8BIT(list));
SET_LEN_VEC8BIT(res, len);
gettab = GETELT_FIELDINFO_8BIT(info);
settab = SETELT_FIELDINFO_8BIT(info);
ptrS = CONST_BYTES_VEC8BIT(list);
ptrD = BYTES_VEC8BIT(res);
e = 0;
byte = 0;
p = low - 1; // the -1 converts to 0 base if (p % elts == 0 && inc == 1 && len >= elts) { while (p < low + len - elts) {
*ptrD++ = ptrS[p / elts];
p += elts;
}
byte = 0;
e = 0; if (p < low + len - 1) { while (p < low + len - 1) {
elt = gettab[ptrS[p / elts] + 256 * (p % elts)];
byte = settab[byte + 256 * (e + elts * elt)];
e++;
p++;
}
*ptrD = byte;
}
} else { for (i = 1; i <= len; i++) {
elt = gettab[ptrS[p / elts] + 256 * (p % elts)];
byte = settab[byte + 256 * (e + elts * elt)];
e++; if (e == elts) {
*ptrD++ = byte;
e = 0;
byte = 0;
}
p += inc;
} if (e)
*ptrD = byte;
}
return res;
}
/**************************************************************************** ** *F FuncASS_VEC8BIT( <self>, <list>, <pos>, <elm> ) ass. elm of 8bit vector ** ** 'ASS_VEC8BIT' assigns the element <elm> at the position <pos> to the ** 8bit vector <list>. ** ** It is the responsibility of the caller to ensure that <pos> is positive, ** and that <elm> is not 0.
*/
// check that <list> is mutable
RequireMutable("List Assignment", list, "list");
// get the position
p = GetPositiveSmallInt("ASS_VEC8BIT", pos);
info = GetFieldInfo8Bit(FIELD_VEC8BIT(list));
elts = ELS_BYTE_FIELDINFO_8BIT(info);
chr = P_FIELDINFO_8BIT(info);
d = D_FIELDINFO_8BIT(info);
q = Q_FIELDINFO_8BIT(info);
if (p <= LEN_VEC8BIT(list) + 1) { if (LEN_VEC8BIT(list) + 1 == p) { if (True == DoFilter(IsLockedRepresentationVector, list)) {
ErrorReturnVoid("List assignment would increase length of " "locked compressed vector",
0, 0, "You can `return;' to ignore the assignment"); return;
}
ResizeWordSizedBag(list, SIZE_VEC8BIT(p, elts));
SET_LEN_VEC8BIT(list, p); // Pr("Extending 8 bit vector by 1",0,0);
} if (!IS_FFE(elm)) {
newelm = DoAttribute(AsInternalFFE, elm); if (newelm != Fail)
elm = newelm;
} if (IS_FFE(elm) && chr == CharFFE(elm)) {
// We may need to rewrite the vector over a larger field if (d % DegreeFFE(elm) != 0) { // Pr("Rewriting over larger field",0,0);
f = CommonFF(FiniteField(chr, d), d, FLD_FFE(elm),
DegreeFFE(elm)); if (f && SIZE_FF(f) <= 256) {
RewriteVec8Bit(list, SIZE_FF(f));
info = GetFieldInfo8Bit(FIELD_VEC8BIT(list));
elts = ELS_BYTE_FIELDINFO_8BIT(info);
chr = P_FIELDINFO_8BIT(info);
d = D_FIELDINFO_8BIT(info);
q = Q_FIELDINFO_8BIT(info);
} else {
PlainVec8Bit(list);
AssPlistFfe(list, p, elm); return;
}
}
v = VAL_FFE(elm);
// may need to promote the element to a bigger field // or restrict it to a smaller one if (v != 0 && q != SIZE_FF(FLD_FFE(elm))) {
GAP_ASSERT(
((v - 1) * (q - 1)) % (SIZE_FF(FLD_FFE(elm)) - 1) == 0);
v = 1 + (v - 1) * (q - 1) / (SIZE_FF(FLD_FFE(elm)) - 1);
}
// We fall through here if the assignment position is so large // as to leave a hole, or if the object to be assigned is // not of the right characteristic, or would create too large a field
/**************************************************************************** ** *F FuncUNB_VEC8BIT( <self>, <list>, <pos> ) unbind position of a GFQ vector ** ** 'UNB_VEC8BIT' unbind the element at the position <pos> in a GFQ vector ** <list>. ** ** It is the responsibility of the caller to ensure that <pos> is positive.
*/ static Obj FuncUNB_VEC8BIT(Obj self, Obj list, Obj pos)
{
UInt p;
Obj info;
UInt elts;
// check that <list> is mutable
RequireMutable("List Unbind", list, "list"); if (True == DoFilter(IsLockedRepresentationVector, list)) {
ErrorReturnVoid( "Unbind of entry of locked compressed vector is forbidden", 0, 0, "You can `return;' to ignore the assignment"); return 0;
}
// get the position
p = GetPositiveSmallInt(SELF_NAME, pos);
// if we unbind the last position keep the representation if (LEN_VEC8BIT(list) < p) {
;
} elseif (LEN_VEC8BIT(list) == p) { // zero out the last entry first, for safety
info = GetFieldInfo8Bit(FIELD_VEC8BIT(list));
elts = ELS_BYTE_FIELDINFO_8BIT(info);
BYTES_VEC8BIT(list)
[(p - 1) / elts] =
SETELT_FIELDINFO_8BIT(info)[((p - 1) % elts) * 256 +
BYTES_VEC8BIT(list)[(p - 1) / elts]];
ResizeWordSizedBag(list, 3 * sizeof(UInt) + (p + elts - 2) / elts);
SET_LEN_VEC8BIT(list, p - 1);
} else {
PlainVec8Bit(list);
UNB_LIST(list, p);
} return 0;
}
/**************************************************************************** ** *F FuncPOSITION_NONZERO_VEC8BIT( <self>, <list>, <zero> ) . ** ** The pointless zero argument is because this is a method for PositionNot ** It is *not* used in the code and can be replaced by a dummy argument. **
*/
len = LEN_VEC8BIT(list);
info = GetFieldInfo8Bit(FIELD_VEC8BIT(list));
elts = ELS_BYTE_FIELDINFO_8BIT(info);
gettab = GETELT_FIELDINFO_8BIT(info);
nb = (len + elts - 1) / elts;
ptr = CONST_BYTES_VEC8BIT(list);
i = from / elts;
j = from % elts; // might be an initial part byte if (j) { if (i < nb && ptr[i]) for (j = from % elts; j < elts && (i * elts + j < len); j++) if (gettab[256 * j + ptr[i]] != 0) return elts * i + j + 1;
i++;
}
// skip empty bytes while (i < nb && !ptr[i])
i++;
if (i >= nb) return len + 1;
// Found a non-empty byte, locate the entry
byte = ptr[i];
j = 0; while (gettab[byte + 256 * j] == 0)
j++; return elts * i + j + 1;
}
/**************************************************************************** ** *F FuncPROD_VEC8BIT_MATRIX( <self>, <vec>, <mat> ) ** ** Method selection should ensure that <mat> is a matrix of ffes in the ** right characteristic. We aim to be fast in the case where it is ** actually a plain list of vec8bits over the same field as <vec>. We also ** know that <vec> and <mat> are non-empty **
*/ static Obj FuncPROD_VEC8BIT_MATRIX(Obj self, Obj vec, Obj mat)
{
Obj res;
Obj info;
UInt q;
UInt len, l2;
UInt len1;
Obj row1;
UInt i;
UInt elts; const UInt1 * gettab; const Obj * ffefelt;
Obj x;
len = LEN_VEC8BIT(vec);
l2 = LEN_PLIST(mat);
q = FIELD_VEC8BIT(vec);
// Get the first row, to establish the size of the result
row1 = ELM_PLIST(mat, 1); if (!IS_VEC8BIT_REP(row1) || FIELD_VEC8BIT(row1) != q) return TRY_NEXT_METHOD;
len1 = LEN_VEC8BIT(row1);
// create the result space
res = ZeroVec8Bit(q, len1, IS_MUTABLE_OBJ(vec) || IS_MUTABLE_OBJ(row1));
// Finally, we start work
info = GetFieldInfo8Bit(q);
elts = ELS_BYTE_FIELDINFO_8BIT(info);
gettab = GETELT_FIELDINFO_8BIT(info);
ffefelt = CONST_FFE_FELT_FIELDINFO_8BIT(info);
for (i = 0; i < len; i++) if (i < l2) {
x = ffefelt[gettab[CONST_BYTES_VEC8BIT(vec)[i / elts] +
256 * (i % elts)]]; if (VAL_FFE(x) != 0) {
row1 = ELM_PLIST(mat, i + 1); // This may be unduly draconian. Later we may want to be able // to promote the rows to a bigger field if ((!IS_VEC8BIT_REP(row1)) || (FIELD_VEC8BIT(row1) != q)) return TRY_NEXT_METHOD;
AddVec8BitVec8BitMultInner(res, res, row1, x, 1, len1);
}
} return res;
}
/**************************************************************************** ** *F * * * * * * * special rep for matrices over these fields * * * * * * *
*/
/**************************************************************************** ** *F FuncCONV_MAT8BIT( <self>, <list> , <q> ) ** ** The library should have taken care of <list> containing only locked ** 8 bit vectors, written over the correct field
*/
UInt iq = GetPositiveSmallInt(SELF_NAME, q);
PLAIN_LIST(list);
len = LEN_PLIST(list);
mut = IS_MUTABLE_OBJ(list);
GROW_PLIST(list, len + 1); for (i = len; i >= 1; i--) {
tmp = ELM_PLIST(list, i); if (!IS_VEC8BIT_REP(tmp)) {
ErrorMayQuit("CONV_MAT8BIT: argument must be a list of " "compressed 8bit vectors", 0, 0);
}
type = TypeVec8BitLocked(iq, IS_MUTABLE_OBJ(tmp));
SetTypeDatObj(tmp, type);
SET_ELM_MAT8BIT(list, i, tmp);
CHANGED_BAG(list);
}
SET_LEN_MAT8BIT(list, len);
RetypeBag(list, T_POSOBJ);
type = TypeMat8Bit(iq, mut);
SET_TYPE_POSOBJ(list, type); return 0;
}
/**************************************************************************** ** *F ProdVec8BitMat8Bit( <vec>, <mat> ) ** ** The caller must ensure that <vec> and <mat> are compatible
*/
// Finally, we start work
info = GetFieldInfo8Bit(q);
elts = ELS_BYTE_FIELDINFO_8BIT(info);
gettab = GETELT_FIELDINFO_8BIT(info);
ffefelt = CONST_FFE_FELT_FIELDINFO_8BIT(info);
bptr = CONST_BYTES_VEC8BIT(vec); for (i = 0; i + elts < len; i += elts, bptr++) { if ((byte = *bptr)) { for (j = 0; j < elts; j++) { if (i + j < lenm) {
y = gettab[byte + 256 * j]; if (y) {
x = ffefelt[y];
row1 = ELM_MAT8BIT(mat, i + j + 1);
AddVec8BitVec8BitMultInner(res, res, row1, x, 1,
len1);
}
}
}
}
} if ((byte = *bptr)) { for (j = 0; i + j < len; j++) { if (i + j < lenm) {
y = gettab[byte + 256 * j]; if (y) {
x = ffefelt[y];
row1 = ELM_MAT8BIT(mat, i + j + 1);
AddVec8BitVec8BitMultInner(res, res, row1, x, 1, len1);
}
}
}
} return res;
}
/**************************************************************************** ** *F FuncPROD_VEC8BIT_MAT8BIT( <self>, <vec>, <mat> ) ** ** The caller should ensure that characteristics are right and that the ** arguments ARE an 8 bit vector and matrix. We still have to check actual ** fields and lengths.
*/
len = LEN_MAT8BIT(mat);
q = FIELD_VEC8BIT(vec); // TODO(0xn)
row1 = ELM_MAT8BIT(mat, 1);
GAP_ASSERT(q == FIELD_MAT8BIT(mat));
res = ZeroVec8Bit(q, len, IS_MUTABLE_OBJ(row1) || IS_MUTABLE_OBJ(vec));
info = GetFieldInfo8Bit(q);
settab = SETELT_FIELDINFO_8BIT(info);
elts = ELS_BYTE_FIELDINFO_8BIT(info);
feltffe = FELT_FFE_FIELDINFO_8BIT(info);
byte = 0;
ptr = BYTES_VEC8BIT(res); for (i = 0; i < len; i++) {
entry = ScalarProductVec8Bits(vec, ELM_MAT8BIT(mat, i + 1));
byte =
settab[byte + 256 * (elts * feltffe[VAL_FFE(entry)] + i % elts)]; if (i % elts == elts - 1) {
*ptr++ = byte;
byte = 0;
}
} if (len % elts != 0)
*ptr++ = byte; return res;
}
/**************************************************************************** ** *F FuncPROD_MAT8BIT_VEC8BIT( <self>, <mat>, <vec> ) ** ** The caller should ensure that characteristics are right and that the ** arguments ARE an 8 bit vector and matrix. We still have to check actual ** fields and lengths.
*/
prod = NewWordSizedBag(T_POSOBJ, sizeof(Obj) * (len + 2));
SET_LEN_MAT8BIT(prod, len);
type = TypeMat8Bit(q, IS_MUTABLE_OBJ(matl) || IS_MUTABLE_OBJ(matr));
SET_TYPE_POSOBJ(prod, type);
locked_type = TypeVec8BitLocked(
q, IS_MUTABLE_OBJ(ELM_MAT8BIT(matl, 1)) // FIXME(0xn)
|| IS_MUTABLE_OBJ(ELM_MAT8BIT(matr, 1))); for (i = 1; i <= len; i++) {
row = ProdVec8BitMat8Bit(ELM_MAT8BIT(matl, i), matr);
// Since I'm going to put this vector into a matrix, I must lock its // representation, so that it doesn't get rewritten over GF(q^k)
SetTypeDatObj(row, locked_type);
SET_ELM_MAT8BIT(prod, i, row);
CHANGED_BAG(prod);
TakeInterrupt();
} return prod;
}
// set up cmat and inv. Note that the row numbering is offset
cmat = NEW_PLIST(T_PLIST, len);
zero = ZeroVec8Bit(q, len, 1);
o = FELT_FFE_FIELDINFO_8BIT(info)[1]; for (i = 1; i <= len; i++) {
row = ELM_MAT8BIT(mat, i);
row = SHALLOW_COPY_OBJ(row);
SET_ELM_PLIST(cmat, i, row);
CHANGED_BAG(cmat);
row = SHALLOW_COPY_OBJ(zero);
ptr = BYTES_VEC8BIT(row) + (i - 1) / elts;
// we can't retain this pointer, because of garbage collections
settab = SETELT_FIELDINFO_8BIT(info); // we know we are replacing a zero
*ptr = settab[256 * ((i - 1) % elts + o * elts)];
SET_ELM_PLIST(inv, i + 1, row);
CHANGED_BAG(inv);
}
// Now do Gaussian elimination in cmat and mirror it on inv // from here, no garbage collections are allowed until the end
gettab = GETELT_FIELDINFO_8BIT(info);
ffefelt = CONST_FFE_FELT_FIELDINFO_8BIT(info);
for (i = 1; i <= len; i++) {
off = (i - 1) / elts;
pos = (i - 1) % elts; // find a non-zero entry in column i for (j = i; j <= len; j++) {
row = ELM_PLIST(cmat, j);
byte = CONST_BYTES_VEC8BIT(row)[off]; if (byte != 0 && (x = gettab[byte + 256 * pos]) != 0) break;
}
// if we didn't find one if (j > len) return Fail;
// swap and normalize
row1 = ELM_PLIST(inv, j + 1); if (i != j) {
SET_ELM_PLIST(cmat, j, ELM_PLIST(cmat, i));
SET_ELM_PLIST(cmat, i, row);
SET_ELM_PLIST(inv, j + 1, ELM_PLIST(inv, i + 1));
SET_ELM_PLIST(inv, i + 1, row1);
} if (x != o) {
xi = INV(ffefelt[x]);
MultVec8BitFFEInner(row, row, xi, i, len);
MultVec8BitFFEInner(row1, row1, xi, 1, len);
}
// Now clean out column for (k = 1; k <= len; k++) { if (k < i || k > j) {
row2 = ELM_PLIST(cmat, k);
byte = CONST_BYTES_VEC8BIT(row2)[off]; if (byte != 0 && (x = gettab[byte + 256 * pos]) != 0) {
xn = AINV_SAMEMUT(ffefelt[x]);
AddVec8BitVec8BitMultInner(row2, row2, row, xn, i, len);
row2 = ELM_PLIST(inv, k + 1);
AddVec8BitVec8BitMultInner(row2, row2, row1, xn, 1, len);
}
}
} if (TakeInterrupt()) {
gettab = GETELT_FIELDINFO_8BIT(info);
ffefelt = CONST_FFE_FELT_FIELDINFO_8BIT(info);
}
}
// Now clean up inv and return it
SET_ELM_PLIST(inv, 1, INTOBJ_INT(len));
type = TypeVec8BitLocked(
q, mut == 2 || (mut == 1 && IS_MUTABLE_OBJ(ELM_MAT8BIT(mat, 1)))); for (i = 2; i <= len + 1; i++) {
row = ELM_PLIST(inv, i);
SetTypeDatObj(row, type);
}
RetypeBag(inv, T_POSOBJ);
type = TypeMat8Bit(q, mut == 2 || (mut == 1 && IS_MUTABLE_OBJ(mat)));
SET_TYPE_POSOBJ(inv, type);
CHANGED_BAG(inv); return inv;
}
if (LEN_MAT8BIT(mat) != LEN_VEC8BIT(ELM_MAT8BIT(mat, 1))) {
ErrorMayQuit("InverseOp: matrix must be square, not %d by %d",
LEN_MAT8BIT(mat), LEN_VEC8BIT(ELM_MAT8BIT(mat, 1)));
}
UInt r1 = GetSmallInt(SELF_NAME, row1);
UInt r2 = GetSmallInt(SELF_NAME, row2);
UInt m = LEN_MAT8BIT(mat); if (m < r1) {
ErrorMayQuit("row index %d exceeds %d, the number of rows", r1, m);
} if (m < r2) {
ErrorMayQuit("row index %d exceeds %d, the number of rows", r2, m);
}
Obj a = ELM_MAT8BIT(mat, r1);
Obj b = ELM_MAT8BIT(mat, r2);
UInt n = LEN_VEC8BIT(ELM_MAT8BIT(mat, 1)); if (n < c1) {
ErrorMayQuit("column index %d exceeds %d, the number of columns", c1, n);
} if (n < c2) {
ErrorMayQuit("column index %d exceeds %d, the number of columns", c2, n);
}
for (UInt i = 1; i <= m; ++i) {
Obj vec = ELM_MAT8BIT(mat, i); if (!IS_MUTABLE_OBJ(vec)) {
ErrorMayQuit("row %d is immutable", i, 0);
} if (LEN_VEC8BIT(vec) != n) {
ErrorMayQuit("row length mismatch, %d versus %d", n, LEN_VEC8BIT(vec));
}
Obj a = FuncELM_VEC8BIT(self, vec, col1);
Obj b = FuncELM_VEC8BIT(self, vec, col2); if (a != b) {
ASS_VEC8BIT(vec, col1, b);
ASS_VEC8BIT(vec, col2, a);
}
}
return 0;
}
/**************************************************************************** ** *F SumMat8BitMat8Bit( <ml> ,<mr>) ** ** Caller's job to do all checks
*/
type = TypeVec8BitLocked(q, IS_MUTABLE_OBJ(ELM_MAT8BIT(ml, 1)) ||
IS_MUTABLE_OBJ(ELM_MAT8BIT(mr, 1)));
for (i = 1; i <= ls; i++) { if (i > ll)
row = CopyVec8Bit(ELM_MAT8BIT(mr, i), 1); elseif (i > lr)
row = CopyVec8Bit(ELM_MAT8BIT(ml, i), 1); else
row = SumVec8BitVec8Bit(ELM_MAT8BIT(ml, i), ELM_MAT8BIT(mr, i));
SetTypeDatObj(row, type);
SET_ELM_MAT8BIT(sum, i, row);
CHANGED_BAG(sum);
} return sum;
}
/**************************************************************************** ** *F FuncSUM_MAT8BIT_MAT8BIT( <self>, <ml>, <mr> ) ** ** Caller should check that both args are mat8bit over the same field
*/
/**************************************************************************** ** *F DiffMat8BitMat8Bit( <ml> ,<mr>) ** ** Caller's job to do all checks
*/
for (i = 1; i <= ld; i++) { if (i > ll)
row = MultVec8BitFFE(ELM_MAT8BIT(mr, i), mone); elseif (i > lr)
row = CopyVec8Bit(ELM_MAT8BIT(ml, i), 1); else
row = SumVec8BitVec8BitMult(ELM_MAT8BIT(ml, i),
ELM_MAT8BIT(mr, i), mone);
SetTypeDatObj(row, type);
SET_ELM_MAT8BIT(diff, i, row);
CHANGED_BAG(diff);
} return diff;
}
/**************************************************************************** ** *F FuncDIFF_MAT8BIT_MAT8BIT( <self>, <ml>, <mr> ) ** ** Caller should check that both args are mat8bit over the same field
*/
// handle last byte specially, unless it happens to be full if (len % elts != 0) {
gettab = GETELT_FIELDINFO_8BIT(info) + *ptr; for (i = len % elts - 1; i >= 0; i--) { if (gettab[256 * i] != 0) return (elts * (len / elts) + i + 1);
}
ptr--;
}
// now skip over empty bytes while (ptr >= ptrS && *ptr == 0)
ptr--; if (ptr < ptrS) return 0;
// Now look in the rightmost non-empty byte for the position
gettab = GETELT_FIELDINFO_8BIT(info) + *ptr; for (i = elts - 1; i >= 0; i--) { if (gettab[256 * i] != 0) return (elts * (ptr - ptrS) + i + 1);
}
Panic("this should never happen");
}
if (True == DoFilter(IsLockedRepresentationVector, vec)) {
ErrorReturnVoid("Resize of locked compressed vector is forbidden", 0,
0, "You can `return;' to ignore the operation"); return;
}
q = FIELD_VEC8BIT(vec);
info = GetFieldInfo8Bit(q);
elts = ELS_BYTE_FIELDINFO_8BIT(info);
SET_LEN_VEC8BIT(vec, newlen);
ResizeWordSizedBag(vec, SIZE_VEC8BIT(newlen, elts)); // vector has got shorter. if (len > newlen) { if (newlen % elts) { // clean spare entries in last byte
settab = SETELT_FIELDINFO_8BIT(info);
byte = CONST_BYTES_VEC8BIT(vec)[(newlen - 1) / elts]; for (i = newlen % elts; i < elts; i++)
byte = settab[byte + 256 * i];
BYTES_VEC8BIT(vec)[(newlen - 1) / elts] = byte;
} // Clean spare bytes in last word for characteristic 2 if ((q % 2) == 0) for (i = (newlen + elts - 1) / elts; i % sizeof(UInt); i++)
BYTES_VEC8BIT(vec)[i] = 0;
}
// vector has got longer and might be dirty if (!knownclean && newlen > len) {
settab = SETELT_FIELDINFO_8BIT(info);
ptr = BYTES_VEC8BIT(vec); if (len) {
ptr += (len - 1) / elts;
byte = *ptr; for (i = (len - 1) % elts + 1; i < elts; i++)
byte = settab[byte + 256 * i];
*ptr++ = byte;
}
ptr2 = BYTES_VEC8BIT(vec) + (newlen + elts - 1) / elts; while (ptr < ptr2)
*ptr++ = (UInt1)0;
}
}
// The easy case is just a shift by bytes if (amount % elts == 0) { while (ptr2 < end)
*ptr1++ = *ptr2++;
} else { // The general case
from = amount;
to = 0;
fbyte = *ptr2;
tbyte = 0;
gettab = GETELT_FIELDINFO_8BIT(info);
settab = SETELT_FIELDINFO_8BIT(info);
// The easy case is just a shift by bytes if (amount % elts == 0) {
end = BYTES_VEC8BIT(vec); while (ptr2 >= end)
*ptr1-- = *ptr2--; while (ptr1 >= end)
*ptr1-- = (UInt1)0;
} else { // The general case
from = len - 1;
to = len + amount - 1;
fbyte = *ptr2;
tbyte = 0;
gettab = GETELT_FIELDINFO_8BIT(info);
settab = SETELT_FIELDINFO_8BIT(info);
/**************************************************************************** ** *F FuncADD_COEFFS_VEC8BIT_3( <self>, <vec1>, <vec2>, <mult> ) ** ** This is very like AddRowVector, except that it will enlarge <vec1> if ** necessary and returns the position of the rightmost non-zero entry in the ** result.
*/
// Now we know that the characteristics must match, but not the fields
q = FIELD_VEC8BIT(vec1);
// fix up fields if necessary if (q != FIELD_VEC8BIT(vec2) || q != SIZE_FF(FLD_FFE(mult))) {
Obj info, info1;
UInt d, d1, q1, d2, d0, q0, p, i;
FFV val; // find a common field
info = GetFieldInfo8Bit(q);
d = D_FIELDINFO_8BIT(info);
q1 = FIELD_VEC8BIT(vec2);
info1 = GetFieldInfo8Bit(q1);
d1 = D_FIELDINFO_8BIT(info1);
d2 = DegreeFFE(mult);
d0 = LcmDegree(d, d1);
d0 = LcmDegree(d0, d2);
p = P_FIELDINFO_8BIT(info);
GAP_ASSERT(p == P_FIELDINFO_8BIT(info1));
GAP_ASSERT(p == CHAR_FF(FLD_FFE(mult)));
q0 = 1; for (i = 0; i < d0; i++)
q0 *= p;
// if the exponent is bigger than 31, overflow changes the value to 0 if (d0 > 8 || q0 > 256) return TRY_NEXT_METHOD; if ((q0 > q &&
CALL_1ARGS(IsLockedRepresentationVector, vec1) == True) ||
(q0 > q1 &&
CALL_1ARGS(IsLockedRepresentationVector, vec2) == True)) return TRY_NEXT_METHOD;
RewriteVec8Bit(vec1, q0);
RewriteVec8Bit(vec2, q0);
val = VAL_FFE(mult); if (val != 0)
val = 1 + (val - 1) * (q0 - 1) / (SIZE_FF(FLD_FFE(mult)) - 1);
mult = NEW_FFE(FiniteField(p, d0), val);
q = q0;
}
AddVec8BitVec8BitMultInner(vec1, vec1, vec2, mult, 1, len); return INTOBJ_INT(RightMostNonZeroVec8Bit(vec1));
}
/**************************************************************************** ** *F FuncADD_COEFFS_VEC8BIT_2( <self>, <vec1>, <vec2> ) ** ** This is very like AddRowVector, except that it will enlarge <vec1> if ** necessary and returns the position of the rightmost non-zero entry in the ** result.
*/
// find a common field
info = GetFieldInfo8Bit(q);
d = D_FIELDINFO_8BIT(info);
q1 = FIELD_VEC8BIT(vr);
info1 = GetFieldInfo8Bit(q1);
d1 = D_FIELDINFO_8BIT(info1);
d0 = LcmDegree(d, d1);
p = P_FIELDINFO_8BIT(info);
GAP_ASSERT(p == P_FIELDINFO_8BIT(info1));
q0 = 1; for (i = 0; i < d0; i++)
q0 *= p;
// if the exponent is bigger than 31, overflow changes the value to 0 if (d0 > 8 || q0 > 256) return TRY_NEXT_METHOD; if ((q0 > q &&
CALL_1ARGS(IsLockedRepresentationVector, vl) == True) ||
(q0 > q1 && CALL_1ARGS(IsLockedRepresentationVector, vr) == True)) return TRY_NEXT_METHOD;
RewriteVec8Bit(vl, q0);
RewriteVec8Bit(vr, q0);
q = q0;
}
RequireNonnegativeSmallInt(SELF_NAME, ll);
RequireNonnegativeSmallInt(SELF_NAME, lr);
ll1 = INT_INTOBJ(ll);
lr1 = INT_INTOBJ(lr); if (0 > ll1 || ll1 > LEN_VEC8BIT(vl))
ErrorQuit("ProdCoeffs: given length <ll> of left argt (%d) is " "negative or longer than the argt (%d)",
INT_INTOBJ(ll), LEN_VEC8BIT(vl)); if (0 > lr1 || lr1 > LEN_VEC8BIT(vr))
ErrorQuit("ProdCoeffs: given length <lr> of right argt (%d) is " "negative or longer than the argt (%d)",
INT_INTOBJ(lr), LEN_VEC8BIT(vr));
info = GetFieldInfo8Bit(q); if (ll1 == 0 && lr1 == 0)
lenp = 0; else
lenp = ll1 + lr1 - 1;
res = ZeroVec8Bit(q, lenp, 1);
ProdCoeffsVec8Bit(res, vl, ll1, vr, lr1);
last = RightMostNonZeroVec8Bit(res); if (last != lenp)
ResizeVec8Bit(res, last, 1); return res;
}
// normalize a copy of v in vn -- normalize means monic, and actual length // equal to length parameter
vn = CopyVec8Bit(v, 1);
ResizeVec8Bit(vn, len, 0);
len1 = (len == 0) ? 0 : RightMostNonZeroVec8Bit(vn); if (len1 == 0)
ErrorReturnVoid("Zero coefficient vector for reduction", 0, 0, "you can 'return;'"); if (len1 != len) {
ResizeVec8Bit(vn, len1, 1);
len = len1;
}
// Now we start to build up the result
shifts = NEW_PLIST_IMM(T_PLIST_TAB, elts + 2);
SET_ELM_PLIST(shifts, elts + 1, INTOBJ_INT(len));
SET_ELM_PLIST(shifts, elts + 2, xi);
SET_LEN_PLIST(shifts, elts + 2);
// vn can simply be stored in one place
SET_ELM_PLIST(shifts, (len - 1) % elts + 1, vn);
CHANGED_BAG(shifts);
if (elts > 1) { // fill the rest up with zero vectors of suitable lengths for (i = 1; i < elts; i++) {
ashift = ZeroVec8Bit(q, len + i, 0);
SET_ELM_PLIST(shifts, (len + i - 1) % elts + 1, ashift);
CHANGED_BAG(shifts);
}
// reload the tables, in case there was a garbage collection
gettab = GETELT_FIELDINFO_8BIT(info);
settab = SETELT_FIELDINFO_8BIT(info); // Now run through the entries of vn inserting them into the shifted // versions
ptr = BYTES_VEC8BIT(vn); for (j = 1; j < elts; j++)
ptrs[j] =
BYTES_VEC8BIT(ELM_PLIST(shifts, (len + j - 1) % elts + 1)); for (i = 0; i < len; i++) {
x = gettab[*ptr + 256 * (i % elts)]; if (x != 0) { for (j = 1; j < elts; j++) {
*(ptrs[j]) = settab[*(ptrs[j]) +
256 * ((i + j) % elts + elts * x)];
}
} if (i % elts == elts - 1)
ptr++; else
ptrs[elts - 1 - (i % elts)]++;
}
} #ifdef HPCGAP for (i = 1; i <= elts; i++)
MakeBagReadOnly(ELM_PLIST(shifts, i));
MakeBagReadOnly(shifts); #endif return shifts;
}
/**************************************************************************** ** *F FuncREDUCE_COEFFS_VEC8BIT( <self>, <vl>, <ll>, <vr>, <lr> ) ** ** NB note that these are not methods and MAY NOT return TRY_NEXT_METHOD
*/
static Obj FuncMAKE_SHIFTED_COEFFS_VEC8BIT(Obj self, Obj vr, Obj lr)
{
RequireVec8BitRep(SELF_NAME, vr);
RequireNonnegativeSmallInt(SELF_NAME, lr); if (INT_INTOBJ(lr) > LEN_VEC8BIT(vr)) {
ErrorQuit("ReduceCoeffs: given length <lr> of right argt (%d) is " "longer than the argt (%d)",
INT_INTOBJ(lr), LEN_VEC8BIT(vr));
} return MakeShiftedVecs(vr, INT_INTOBJ(lr));
}
q = FIELD_VEC8BIT(vl); if (q != FIELD_VEC8BIT(ELM_PLIST(vrshifted, 1))) return Fail;
RequireNonnegativeSmallInt(SELF_NAME, ll); if (INT_INTOBJ(ll) > LEN_VEC8BIT(vl)) {
ErrorQuit("QuotRemCoeffs: given length <ll> of left argt (%d) is " "longer than the argt (%d)",
INT_INTOBJ(ll), LEN_VEC8BIT(vl));
}
ill = INT_INTOBJ(ll);
rem = CopyVec8Bit(vl, 1);
info = GetFieldInfo8Bit(q);
ResizeVec8Bit(rem, ill, 0);
elts = ELS_BYTE_FIELDINFO_8BIT(info);
lr = INT_INTOBJ(ELM_PLIST(vrshifted, elts + 1));
quot = NewWordSizedBag(T_DATOBJ, SIZE_VEC8BIT(ill - lr + 1, elts));
type = TypeVec8Bit(q, 1);
SetTypeDatObj(quot, type);
SET_FIELD_VEC8BIT(quot, q);
SET_LEN_VEC8BIT(quot, ill - lr + 1);
ReduceCoeffsVec8Bit(rem, vrshifted, quot);
ret = NEW_PLIST(T_PLIST_TAB, 2);
SET_LEN_PLIST(ret, 2);
SET_ELM_PLIST(ret, 1, quot);
SET_ELM_PLIST(ret, 2, rem);
CHANGED_BAG(ret); return ret;
}
/**************************************************************************** ** *F Obj SemiechelonListVec8Bits( <mat>, <transformationneeded> ) ** ** ** This is essentially a method for SemiEchelonMat or ** SemiEchelonMatTransformation. ** ** <mat> is assumed by this point to be a list of mutable 8 bit vectors over ** the same field, which can be overwritten if necessary
*/
// Find the field info
q = FIELD_VEC8BIT(ELM_PLIST(mat, 1));
info = GetFieldInfo8Bit(q);
elts = ELS_BYTE_FIELDINFO_8BIT(info);
// Get the Felt numbers for zero and one
convtab = FELT_FFE_FIELDINFO_8BIT(info);
zero = convtab[0];
one = convtab[1];
// Set up the lists for the results
heads = NEW_PLIST(T_PLIST_CYC, ncols);
SET_LEN_PLIST(heads, ncols);
vectors = NEW_PLIST(T_PLIST_TAB_RECT, nrows);
nvecs = 0; if (TransformationsNeeded) {
coeffs = NEW_PLIST(T_PLIST_TAB_RECT, nrows);
relns = NEW_PLIST(T_PLIST_TAB_RECT, nrows);
nrels = 0;
} for (i = 1; i <= ncols; i++)
SET_ELM_PLIST(heads, i, INTOBJ_INT(0));
// Main loop starts here for (i = 1; i <= nrows; i++) {
row = ELM_PLIST(mat, i); if (TransformationsNeeded) {
coeffrow = NewWordSizedBag(T_DATOBJ, SIZE_VEC8BIT(nrows, elts));
SET_LEN_VEC8BIT(coeffrow, nrows);
type = TypeVec8Bit(q, 1);
SetTypeDatObj(coeffrow, type);
SET_FIELD_VEC8BIT(coeffrow, q);
CHANGED_BAG(coeffrow);
// No garbage collection risk from here
settab = SETELT_FIELDINFO_8BIT(info);
BYTES_VEC8BIT(coeffrow)
[(i - 1) / elts] = settab[256 * ((i - 1) % elts + elts * one)];
} // No garbage collection risk from here
gettab = GETELT_FIELDINFO_8BIT(info);
convtab1 = CONST_FFE_FELT_FIELDINFO_8BIT(info);
// Clear out the current row for (j = 1; j <= ncols; j++) {
h = INT_INTOBJ(ELM_PLIST(heads, j)); if (h != 0) {
byte = CONST_BYTES_VEC8BIT(row)[(j - 1) / elts]; if (byte &&
zero != (x = gettab[byte + 256 * ((j - 1) % elts)])) {
y = AINV_SAMEMUT(convtab1[x]);
AddVec8BitVec8BitMultInner(
row, row, ELM_PLIST(vectors, h), y, 1, ncols); if (TransformationsNeeded)
AddVec8BitVec8BitMultInner(coeffrow, coeffrow,
ELM_PLIST(coeffs, h), y, 1,
nrows);
}
}
}
j = 1;
rowp = CONST_BYTES_VEC8BIT(row); while (j <= ncols && !*rowp) {
j += elts;
rowp++;
} while (j <= ncols &&
(zero == (x = gettab[*rowp + 256 * ((j - 1) % elts)])))
j++;
if (j <= ncols) {
y = INV(convtab1[x]);
MultVec8BitFFEInner(row, row, y, 1, ncols);
SET_ELM_PLIST(vectors, ++nvecs, row);
CHANGED_BAG(vectors);
SET_LEN_PLIST(vectors, nvecs);
SET_ELM_PLIST(heads, j, INTOBJ_INT(nvecs)); if (TransformationsNeeded) {
MultVec8BitFFEInner(coeffrow, coeffrow, y, 1, nrows);
SET_ELM_PLIST(coeffs, nvecs, coeffrow);
CHANGED_BAG(coeffs);
SET_LEN_PLIST(coeffs, nvecs);
} // garbage collection OK again after here
} elseif (TransformationsNeeded) {
SET_ELM_PLIST(relns, ++nrels, coeffrow);
CHANGED_BAG(relns);
SET_LEN_PLIST(relns, nrels);
}
TakeInterrupt();
} if (RNheads == 0) {
RNheads = RNamName("heads");
RNvectors = RNamName("vectors");
}
res = NEW_PREC(TransformationsNeeded ? 4 : 2);
AssPRec(res, RNheads, heads);
AssPRec(res, RNvectors, vectors); if (LEN_PLIST(vectors) == 0)
RetypeBag(vectors, T_PLIST_EMPTY); if (TransformationsNeeded) { if (RNcoeffs == 0) {
RNcoeffs = RNamName("coeffs");
RNrelns = RNamName("relations");
}
AssPRec(res, RNcoeffs, coeffs); if (LEN_PLIST(coeffs) == 0)
RetypeBag(coeffs, T_PLIST_EMPTY);
AssPRec(res, RNrelns, relns); if (LEN_PLIST(relns) == 0)
RetypeBag(relns, T_PLIST_EMPTY);
}
SortPRecRNam(res); return res;
}
/**************************************************************************** ** *F FuncSEMIECHELON_LIST_VEC8BITS( <self>, <mat> ) ** ** Method for SemiEchelonMat for plain lists of 8 bit vectors ** ** Method selection can guarantee us a plain list of vectors in same char
*/
len = LEN_PLIST(mat); if (!len) return TRY_NEXT_METHOD;
row = ELM_PLIST(mat, 1); if (!IS_VEC8BIT_REP(row)) return TRY_NEXT_METHOD;
q = FIELD_VEC8BIT(row);
width = LEN_VEC8BIT(row); if (width == 0) return TRY_NEXT_METHOD; for (i = 2; i <= len; i++) {
row = ELM_PLIST(mat, i); if (!IS_VEC8BIT_REP(row) || FIELD_VEC8BIT(row) != q ||
LEN_VEC8BIT(row) != width) { return TRY_NEXT_METHOD;
}
} return SemiEchelonListVec8Bits(mat, 0);
}
/**************************************************************************** ** *F FuncSEMIECHELON_LIST_VEC8BITS_TRANSFORMATIONS( <self>, <mat> ) ** ** Method for SemiEchelonMatTransformations for plain lists of 8 bit vectors ** ** Method selection can guarantee us a plain list of vectors in same ** characteristic
*/
len = LEN_PLIST(mat); if (!len) return TRY_NEXT_METHOD;
row = ELM_PLIST(mat, 1); if (!IS_VEC8BIT_REP(row)) return TRY_NEXT_METHOD;
q = FIELD_VEC8BIT(row);
width = LEN_VEC8BIT(row); if (width == 0) return TRY_NEXT_METHOD; for (i = 2; i <= len; i++) {
row = ELM_PLIST(mat, i); if (!IS_VEC8BIT_REP(row) || FIELD_VEC8BIT(row) != q ||
LEN_VEC8BIT(row) != width) { return TRY_NEXT_METHOD;
}
} return SemiEchelonListVec8Bits(mat, 1);
}
/**************************************************************************** ** *F FuncTRIANGULIZE_LIST_VEC8BITS( <self>, <mat> ) ** ** Method for TriangulizeMat for plain lists of 8 bit vectors ** ** Method selection can guarantee us a plain list of vectors in same ** characteristic
*/
len = LEN_PLIST(mat); if (!len) return TRY_NEXT_METHOD;
row = ELM_PLIST(mat, 1); if (!IS_VEC8BIT_REP(row)) return TRY_NEXT_METHOD;
q = FIELD_VEC8BIT(row);
width = LEN_VEC8BIT(row); if (width == 0) return TRY_NEXT_METHOD; for (i = 2; i <= len; i++) {
row = ELM_PLIST(mat, i); if (!IS_MUTABLE_OBJ(row) || !IS_VEC8BIT_REP(row) ||
FIELD_VEC8BIT(row) != q || LEN_VEC8BIT(row) != width) { return TRY_NEXT_METHOD;
}
}
TriangulizeListVec8Bits(mat, 1, (Obj *)0); return (Obj)0;
}
/**************************************************************************** ** *F FuncRANK_LIST_VEC8BITS( <self>, <mat> ) ** ** Method for RankMatDestructive for plain lists of 8 bit vectors ** ** Method selection can guarantee us a plain list of vectors in same ** characteristic
*/
len = LEN_PLIST(mat); if (!len) return TRY_NEXT_METHOD;
row = ELM_PLIST(mat, 1); if (!IS_VEC8BIT_REP(row)) return TRY_NEXT_METHOD;
q = FIELD_VEC8BIT(row);
width = LEN_VEC8BIT(row); if (width == 0) return TRY_NEXT_METHOD; for (i = 2; i <= len; i++) {
row = ELM_PLIST(mat, i); if (!IS_VEC8BIT_REP(row) || FIELD_VEC8BIT(row) != q ||
LEN_VEC8BIT(row) != width) { return TRY_NEXT_METHOD;
}
} return INTOBJ_INT(TriangulizeListVec8Bits(mat, 0, (Obj *)0));
}
/**************************************************************************** ** *F FuncDETERMINANT_LIST_VEC8BITS( <self>, <mat> ) ** ** Method for DeterminantMatDestructive for plain lists of 8 bit vectors ** ** Method selection can guarantee us a plain list of vectors in same ** characteristic
*/
// set entries // run over elts row chunks of the original matrix for (i = 1; i <= l; i += elts) {
imod = (i - 1) / elts;
// run through these rows in chunks, extract the bytes corresponding // to an elts x elts submatrix into vals for (n = 0; n < nrb; n++) { for (j = 0; j < elts; j++) { if ((i + j) > l) {
if (LEN_MAT8BIT(mat) < r) {
ErrorMayQuit("row index %d exceeds %d, the number of rows", r,
LEN_MAT8BIT(mat));
}
Obj vec = ELM_MAT8BIT(mat, r); if (!IS_MUTABLE_OBJ(vec)) {
ErrorMayQuit("row %d is immutable", r, 0);
} if (LEN_VEC8BIT(vec) < c) {
ErrorMayQuit("column index %d exceeds %d, the number of columns", c,
LEN_VEC8BIT(vec));
}
// TODO: replace the following call by direct access? E.g. so that we can // always reject input elements in the "wrong domain"?
ASS_VEC8BIT(vec, col, elm); return 0;
}
/**************************************************************************** ** *F PreSave( <module ) . . . . . . discard big recoverable data before saving ** ** It will get rebuilt automatically, both in the saving workspace and in ** the loaded one and is not endian-safe anyway
*/
staticInt PreSave(StructInitInfo * module)
{
UInt q; for (q = 3; q <= 256; q++)
SET_ELM_PLIST(FieldInfo8Bit, q, (Obj)0);
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.133Bemerkung:
(vorverarbeitet am 2026-05-06)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.