示例#1
0
def test_gen_xi_ref(gen_xi_class, ref, ntests=200):
    xi, xi_ref = gen_xi_class.gen_xi_op_xi, ref.gen_xi_op_xi

    x_old = 0
    for x in xi_samples(ntests):
        for i in range(0, 3):
            res, ref_ = xi(x, i), xi_ref(x, i)
            assert res == ref_, lmap(hex, [i, x, res, ref_])
        assert gen_xi_class.gen_xi_g_gray(x) == ref.gen_xi_g_gray(x)
        assert gen_xi_class.gen_xi_w2_gray(x) == ref.gen_xi_w2_gray(x)
        assert gen_xi_class.gen_xi_g_cocode(x) == ref.gen_xi_g_cocode(x)
        assert gen_xi_class.gen_xi_w2_cocode(x) == ref.gen_xi_w2_cocode(x)
        x_old = x
    xi_short = gen_xi_class.gen_xi_op_xi_short
    to_leech = gen_xi_class.gen_xi_short_to_leech
    to_short = gen_xi_class.gen_xi_leech_to_short
    xi_short_ref = ref.gen_xi_op_xi_short
    to_leech_ref = ref.gen_xi_short_to_leech
    for x in short_samples(ntests):
        xl = to_leech_ref(x)
        assert to_leech(x) == xl, lmap(hex, [x, xl, to_leech(x)])
        x_norm = normalize_short_vector_code(x)
        assert to_short(xl) == x_norm, lmap(hex, [xl, x, x_norm, to_short(xl)])
        for i in range(1, 3):
            ref = xi_short_ref(x, i)
            assert xi_short(x,
                            i) == ref, lmap(hex,
                                            [i, x, xi_short(x, i), ref])
            pass
示例#2
0
    def better_cocode_basis(cls, verbose=False):
        """Returns a good basis of a traversal of the Golay cocode.

        The asserted properties of the cocode basis are as in the
        main comment of module mat24.py.
        """
        def e(i, a):
            v = [0] * 6
            v[i] = a
            return v

        hexa = lmap(e, [2, 2, 1, 1, 0, 0], [2, 1, 2, 1, 2, 1])
        #basis = [0x111111,0x011111,0x110000,0x101000,0x100100,0x100010,]
        basis = [
            0x111111,
            0x1,
            0x110,
            0x1010,
            0x10010,
            0x100010,
        ]
        basis += lmap(cls.hexacode_vector_to_mog, hexa)
        basis = basis[2:] + basis[:2]
        cls.check_cocode_basis(basis)
        return basis
示例#3
0
def test_gen_xi_short(gen_xi_class, ntests):
    xi = gen_xi_class.gen_xi_op_xi
    xi_short = gen_xi_class.gen_xi_op_xi_short
    to_leech = gen_xi_class.gen_xi_short_to_leech
    to_short = gen_xi_class.gen_xi_leech_to_short
    for x in short_samples(ntests):
        xl = to_leech(x)
        x_norm = normalize_short_vector_code(x)
        assert to_short(xl) == x_norm, lmap(hex, [x, xl, x_norm, to_short(xl)])
        for i in range(1, 3):
            continue
            y = xi_short(x, i)
            assert y, lmap(hex, [x, xl, xi(xl, i), y])
            ref = to_short(xi(xl, i))
            assert y == ref, lmap(hex, [x, xl, xi(xl, i), ref, y])
示例#4
0
    def make_aux_table(self):
        """Prepare table for casting out the i-th column in the MOG

        Let col[i], i=0,...,5 is the vector that casts out the entries 
        in the i-th column in the MOG. col[i] is computed from the 
        basis vectors in self.basis with function and_basis().
         
        self.bw_aux_table is a table with 6 entries, where entry i
        is used to compute  col[i] by member function make_aux_table.
        """
        blackwhite = self.blackwhite
        lbw = len(blackwhite)
        bw_combinations = [None] * 6
        bw_dict = dict(zip([0xf << (4 * i) for i in range(6)], range(6)))
        done = False
        for k in range(1, lbw + 1):
            for sgn in iter_ascending_bitweight((1 << k) - 1):
                signs = [(sgn >> i) & 1 for i in range(k)]
                for pos in lmap(bits2list, iter_bitweight(k, 1 << lbw)):
                    basispos = [blackwhite[i] for i in pos]
                    z = list(zip(basispos, signs))
                    res = self.and_basis(z)
                    try:
                        bw_combinations[bw_dict[res]] = z
                        del bw_dict[res]
                        done = not None in bw_combinations
                        if done: break
                    except:
                        pass
                if done: break
            if done: break
        self.bw_aux_table = bw_combinations
        if self.verbose:
            print("bw_comb", bw_combinations)
示例#5
0
def test_inverse():
    print("Testing matrix inversion ...")
    MAXDIM_INVERSE_TEST = 20
    NSIGMA = 4.0
    elementary_testcases = [([3, 2], [3, 2]), ([2, 4, 1], [4, 1, 2])]
    for a, b in elementary_testcases:
        assert bit_mat_inverse(a) == b
        if a != b: assert bit_mat_inverse(b) == a

    n_cases = [0] * (MAXDIM_INVERSE_TEST + 1)
    n_ok = [0.0] * (MAXDIM_INVERSE_TEST + 1)
    for a in inverse_testcases():
        ok, n = False, len(a)
        if n > MAXDIM_INVERSE_TEST:
            continue
        n_cases[n] += 1
        try:
            inv = bit_mat_inverse(a)
            ok = True
            n_ok[n] += 1
        except:
            pass
        if ok:
            unit = [1 << i for i in range(n)]
            prod = bit_mat_mul(a, inv)
            assert prod == unit, (lmap(hex, a), lmap(hex,
                                                     inv), lmap(hex, prod))
    cases_displayed = [10]
    for n in range(1, MAXDIM_INVERSE_TEST):
        if n_cases[n] > 10:
            import math
            N, N_ok = n_cases[n], n_ok[n]
            p = 1.0
            for i in range(1, n + 1):
                p *= 1.0 - 0.5**i
            mu = N * p
            sigma = math.sqrt(N * p * (1.0 - p))
            if n in cases_displayed:
                print(
                    "Dim. %d, %d cases, ratio of invertibles: %.3f, expected: %.3f+-%.3f"
                    % (n, N, N_ok / N, p, sigma / N))
            assert abs(mu - N_ok) < NSIGMA * sigma, (n, p, mu, sigma, N, N_ok)
    print("Matrix inversion test passed")
示例#6
0
    def historical_check(cls, GolayBasis, generate=False):
        """Checks the Golay code basis against basis a stored older basis

        The basis is checked against basis cls.HISTORICAL_REVERSED_BASIS.
        If 'generate' is set, the basis cls.HISTORICAL_REVERSED_BASIS
        is recomputed by function  make_lex_golay_code_basis().
        """
        ref = lmap(reverse24, cls.HISTORICAL_REVERSED_BASIS)
        ref = pivot_binary_high(ref)[0]
        assert GolayBasis == ref
        if generate:
            assert HISTORICAL_REVERSED_BASIS == make_lex_golay_code_basis()
示例#7
0
    def augment_colored_basis(self):
        """Augment self.basis by addding some vectors to the basis.
        
        The augmented vectors are XOR combinations of the basis vectors.
       
        The following tables are computed:

        self.basis_augment is a list of entries, where each entry represents
        an augmented basis vector as a list of the indices of basis vectors.
        The corresponding basis vectors are to be XORed to obtain the new
        basis vector.    

        self.col_aux_table is a list of 5 entries. Here entry i is the
        instruction how to compute the i-th auxiliary vector aux[i] from 
        the basis vectors with member function  and_basis.

        self.out_table is a table of 24 auxiliary vectors. For 
        obtaining the i-th singleteon we have to compute

            col[i >> 2] &  aux[self.out_table[i]] .
        
        Here col[i] is the vector that casts out the entries in the
        i-th column in the MOG. A table for computing col[i] is prepared
        in member function make_aux_table.
        """
        colored = self.colored
        basis_list = []
        value_list = []
        colored_6 = []
        self.basis_augment = []
        done = False
        for pos in lmap(bits2list,
                        iter_ascending_bitweight(1 << len(colored))):
            basispos = [colored[i] for i in pos]
            value = reduce(__xor__, [self.basis[p] for p in basispos], 0)
            if bw24(value) == 12:
                basis_list.append(basispos)
                value_list.append(value)
                for i, val in enumerate(value_list):
                    if bw24(value ^ val) == 12:
                        for j in [i, -1]:
                            b, v = basis_list[j], value_list[j]
                            if len(b) > 1:
                                self.basis_augment.append(b)
                                b = [len(self.basis)]
                                self.basis.append(v)
                                self.colored.append(b)
                            colored_6.append(b[0])
                        done = True
                        break
            if done: break

        c0, c1 = colored_6[0], colored_6[1]
        self.col_aux_table = [[(self.odd_v, 0)], [(self.odd_v, 1)],
                              [(c0, 0), (c1, 0)], [(c0, 0), (c1, 1)],
                              [(c0, 1), (c1, 0)]]
        col_aux_values = lmap(self.and_basis, self.col_aux_table)
        self.out_table = []
        for i in range(24):
            mask = 0xf << (i & -4)
            for j, v in enumerate(col_aux_values):
                if v & mask == 1 << i:
                    self.out_table.append(j)
                    break
        assert len(self.out_table) == 24
        if self.verbose:
            print("augmented basis for Golay code to perm rep of Mat24")
            print(lmap(hex, self.basis))
            print("augment:", self.basis_augment, "col", colored_6)
            print("col_aux_table:", self.col_aux_table)
            print("values:", [hex(x & 0xffffff) for x in col_aux_values])
            print("t_out:", self.out_table)
示例#8
0
class MM_Const(MM_Basics):
    """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 directive ``MMV_LOAD_CONST`` for storing the 
    table of constants, for a specific modulus ``p``, in an integer 
    variable. The string formatting function ``MMV_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 directive 
    ``MMV_CONST_TAB``. 

    Constants not depending on the modulus ``p``, such as ``INT_BITS``, 
    ``LOG_INT_BITS``, and ``MMV_ENTRIES`` are available as attributes 
    of class ``MM_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 on ``p`` 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 function ``shl`` 
    which generates a shift expression  Here::

         %{shl:expression, i}

    generates an expression equivalent to ``((expression) << i)``. 
    Here ``i`` must be an integer. In case ``i < 0`` we generate 
    ``((expression) >> -i)`` instead. E.g. ``%{shl:'x',-3}``
    evaluates to ``x >> 3``.

    Class ``MM_Const`` provides another string-formatting function
    ``smask`` which generates an integer constant to be used as a 
    bit mask for integers of type ``uint_mmv_t``. Here::

         %{smask:value, fields, width}

    with integers ``value``, ``fields``, and ``width`` creates such a 
    bit mask. ``For 0 <= i`` and ``0 <= j < width``, the bit of that 
    mask at  position ``i * width + j`` is set if both, bit ``i`` of 
    the integer ``fields`` and bit ``j`` of the integer ``value`` are 
    set. A bit in the mask at  position ``INT_BITS`` or higher is 
    never set.
    
    Any of the arguments ``value`` and ``fields`` 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 to ``0x330``.
    """
    # Names of the constants to be stored in an integer for each p
    entries = [
        "LOG_INT_FIELDS",
        "INT_FIELDS",
        "LOG_FIELD_BITS",
        "FIELD_BITS",
        "P_BITS",
    ]

    primes = [(1 << k) - 1 for k in range(2, 9)]  # list of all p
    lengths = [0] * len(entries)  # list of max bit length of constants
    for p in primes:
        data = MM_Basics.sizes(p)
        for i, name in enumerate(entries):
            lengths[i] |= data[name]
    lengths = lmap(bitlen, lengths)
    #print ("SUM MM_Const bitlengths", sum(lengths))

    assert sum(lengths) <= 32
    pos = {}  # pos is a dictionary of shape
    start = 0  #  {entry_name:(start_pos,max_value)}
    for i, length in enumerate(lengths):
        pos[entries[i]] = (start, (1 << length) - 1)
        start += length
    deBruijnMult = 0xe8  # deBruijn sequence
    table = [0] * 8  # This will be the table of constants
    for p in primes:  # Assemble that table
        data = MM_Basics.sizes(p)
        index = (((p + 1) * deBruijnMult) >> 8) & 7  # scramble indices of
        # table access via deBruijn sequence
        value = 0
        for entry, (shift, mask) in pos.items():  # assemble entry for p
            assert 0 <= data[entry] <= mask
            value += data[entry] << shift
        table[index] = value  # store entry for p in table
    #print("pos", pos)
    #rint("tbl", lmap(hex,table))
    T_NAME = "MMV_CONST_TAB"  # python name of contant table
    F_NAME = "MMV_CONST"  # function name "MMV_CONST"
    LOAD_F_NAME = "MMV_LOAD_CONST"  # directive name "MMV_LOAD_CONST"

    # Some more constants are definded as  dividend/INT_FIELDS
    # with dividends for contant names given by:
    dividend = {
        "V64_INTS": 64,
        "V24_INTS": 32,
        "MMV_INTS": MM_Basics.MMV_ENTRIES,
    }

    def __init__(self):
        new_tables = {
            self.T_NAME: self.table,
            "P_LIST": config.PRIMES,
            "MMV_CONST": UserFormat(self.f, "ss"),
            "smask": UserFormat(smask, fmt=c_hex),
        }
        self.tables = self.tables.copy()
        self.tables.update(new_tables)
        self.directives = {
            "MMV_LOAD_CONST":
            UserDirective(self.gen_get_const_table, "ss", "NAMES"),
        }
        for name in [
                "P",
                "P_BITS",
                "FIELD_BITS",
                "LOG_FIELD_BITS",
                "INT_FIELDS",
                "LOG_INT_FIELDS",
                "V24_INTS",
                "LOG_V24_INTS",
                "V24_INTS_USED",
                "V64_INTS",
                "LOG_V64_INTS",
        ]:
            f = partial(_attr_from_table, name)
            setattr(self, name, f)
            self.tables[name] = UserFormat(f, "i")

    @classmethod
    def gen_get_const_table(cls, names, p, const_p):
        """Code generating method for directive MMV_LOAD_CONST 

        According to rules of class TableGenerator the first argument 
        of this method may be an implicit dictionary that translates 
        the python name of the table of constants to the C name of that
        table. So names[cls.T_NAME] is the appropriate C name. 
       
        We calculate the index for the given input p and load the
        entry of that table corresponding to p (which is an integer)
        to the destination given by const_p.
        """
        s = "// Store constant table for {p} to {const_p}\n".format(
            const_p=const_p, p=p)
        s += "{c} = {t}[(((({p}) + 1) * {mul}) >> 8) & 7];\n".format(
            c=const_p, p=p, t=names[cls.T_NAME], mul=cls.deBruijnMult)
        return s

    @classmethod
    def gen_get_const_expr(cls, const_name, const_p):
        """General code generating method for function MMV_CONST 

        It generates code that extracts the constant with name 
        const_name from the entry const_p for a specific p. 
        """
        sh, mask = cls.pos[const_name]
        s = "(({t}{sh}) & {mask})".format(t=const_p,
                                          mask=mask,
                                          sh=" >> " + str(sh) if sh else "")
        return s

    @classmethod
    def gen_div_int_fields(cls, const_name, const_p):
        """Code generating for constants with names in self.dividend

        All these constants are defined as dividend/INT_FIELDS.
        The dividents for these contant names are taken from
        dictionary cls.dividend. The constant INT_FIELDS is calculated
        by method  gen_get_const_expr() of this class.
        """
        n_entries = cls.dividend[const_name]
        log_ = cls.gen_get_const_expr("LOG_INT_FIELDS", const_p)
        return "({0} >> {1})".format(n_entries, log_)

    @classmethod
    def f(cls, name, *args):
        """Code generating method for function MMV_CONST 

        It generates code that returns the constant with given
        'name'.
        """
        try:
            return cls.gen_div_int_fields(name, *args)
        except:
            return cls.gen_get_const_expr(name, *args)