예제 #1
0
def _some_tuples_sampling(elements, repeat, max_samples, n):
    """
    Internal function for :func:`some_tuples`.

    TESTS::

        sage: from sage.misc.misc import _some_tuples_sampling
        sage: l = list(_some_tuples_sampling(range(3), 3, 2, 3))
        sage: len(l)
        2
        sage: all(len(tup) == 3 for tup in l)
        True
        sage: all(el in range(3) for tup in l for el in tup)
        True
        sage: l = list(_some_tuples_sampling(range(20), None, 4, 20))
        sage: len(l)
        4
        sage: all(el in range(20) for el in l)
        True
    """
    from sage.rings.integer import Integer
    N = n if repeat is None else n**repeat
    # We sample on range(N) and create tuples manually since we don't want to create the list of all possible tuples in memory
    for a in random.sample(range(N), max_samples):
        if repeat is None:
            yield elements[a]
        else:
            yield tuple(elements[j] for j in Integer(a).digits(n, padto=repeat))
예제 #2
0
    def transmit_unsafe(self, message):
        r"""
        Returns ``message`` with as many errors as ``self._number_errors`` in it.

        If ``self._number_errors`` was passed as a tuple for the number of errors, it will
        pick a random integer between the bounds of the tuple and use it as the number of errors.

        This method does not check if ``message`` belongs to the input space of``self``.

        INPUT:

        - ``message`` -- a vector

        OUTPUT:

        - a vector of the output space

        EXAMPLES::

            sage: F = GF(59)^6
            sage: n_err = 2
            sage: Chan = channels.StaticErrorRateChannel(F, n_err)
            sage: msg = F((4, 8, 15, 16, 23, 42))
            sage: set_random_seed(10)
            sage: Chan.transmit_unsafe(msg)
            (4, 8, 4, 16, 23, 53)
        """
        w = copy(message)
        number_errors = randint(*self.number_errors())
        V = self.input_space()
        for i in sample(xrange(V.dimension()), number_errors):
            w[i] = V.base_ring().random_element()
        return w
예제 #3
0
    def transmit_unsafe(self, message):
        r"""
        Returns ``message`` with as many errors as ``self._number_errors`` in it.

        If ``self._number_errors`` was passed as a tuple for the number of errors, it will
        pick a random integer between the bounds of the tuple and use it as the number of errors.

        This method does not check if ``message`` belongs to the input space of``self``.

        INPUT:

        - ``message`` -- a vector

        OUTPUT:

        - a vector of the output space

        EXAMPLES::

            sage: F = GF(59)^6
            sage: n_err = 2
            sage: Chan = channels.StaticErrorRateChannel(F, n_err)
            sage: msg = F((4, 8, 15, 16, 23, 42))
            sage: set_random_seed(10)
            sage: Chan.transmit_unsafe(msg)
            (4, 8, 4, 16, 23, 53)
        """
        w = copy(message)
        number_errors = randint(*self.number_errors())
        V = self.input_space()
        for i in sample(xrange(V.dimension()), number_errors):
            w[i] = V.base_ring().random_element()
        return w
예제 #4
0
    def transmit_unsafe(self, message):
        r"""
        Returns ``message`` with as many errors as ``self._number_errors`` in it, and as many erasures
        as ``self._number_erasures`` in it.

        If ``self._number_errors`` was passed as an tuple for the number of errors, it will
        pick a random integer between the bounds of the tuple and use it as the number of errors.
        It does the same with ``self._number_erasures``.

        All erased positions are set to 0 in the transmitted message.
        It is guaranteed that the erasures and the errors will never overlap:
        the received message will always contains exactly as many errors and erasures
        as expected.

        This method does not check if ``message`` belongs to the input space of``self``.

        INPUT:

        - ``message`` -- a vector

        OUTPUT:

        - a couple of vectors, namely:

            - the transmitted message, which is ``message`` with erroneous and erased positions
            - the erasure vector, which contains ``1`` at the erased positions of the transmitted message
              , 0 elsewhere.

        EXAMPLES::

            sage: F = GF(59)^11
            sage: n_err, n_era = 2, 2
            sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era)
            sage: msg = F((3, 14, 15, 9, 26, 53, 58, 9, 7, 9, 3))
            sage: set_random_seed(10)
            sage: Chan.transmit_unsafe(msg)
            ((31, 0, 15, 9, 38, 53, 58, 9, 0, 9, 3), (0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0))
        """
        number_errors = randint(*self.number_errors())
        number_erasures = randint(*self.number_erasures())
        V = self.input_space()
        n = V.dimension()
        zero = V.base_ring().zero()

        errors = sample(xrange(n), number_errors + number_erasures)
        error_positions   = errors[:number_errors]
        erasure_positions = errors[number_errors:]

        error_vector = random_error_vector(n, V.base_ring(), error_positions)
        erasure_vector = random_error_vector(n , GF(2), erasure_positions)

        message = message + error_vector

        for i in erasure_positions:
            message[i] = zero
        return message, erasure_vector
예제 #5
0
    def transmit_unsafe(self, message):
        r"""
        Returns ``message`` with as many errors as ``self._number_errors`` in it, and as many erasures
        as ``self._number_erasures`` in it.

        If ``self._number_errors`` was passed as an tuple for the number of errors, it will
        pick a random integer between the bounds of the tuple and use it as the number of errors.
        It does the same with ``self._number_erasures``.

        All erased positions are set to 0 in the transmitted message.
        It is guaranteed that the erasures and the errors will never overlap:
        the received message will always contains exactly as many errors and erasures
        as expected.

        This method does not check if ``message`` belongs to the input space of``self``.

        INPUT:

        - ``message`` -- a vector

        OUTPUT:

        - a couple of vectors, namely:

            - the transmitted message, which is ``message`` with erroneous and erased positions
            - the erasure vector, which contains ``1`` at the erased positions of the transmitted message
              , 0 elsewhere.

        EXAMPLES::

            sage: F = GF(59)^11
            sage: n_err, n_era = 2, 2
            sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era)
            sage: msg = F((3, 14, 15, 9, 26, 53, 58, 9, 7, 9, 3))
            sage: set_random_seed(10)
            sage: Chan.transmit_unsafe(msg)
            ((31, 0, 15, 9, 38, 53, 58, 9, 0, 9, 3), (0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0))
        """
        number_errors = randint(*self.number_errors())
        number_erasures = randint(*self.number_erasures())
        V = self.input_space()
        n = V.dimension()
        zero = V.base_ring().zero()

        errors = sample(xrange(n), number_errors + number_erasures)
        error_positions = errors[:number_errors]
        erasure_positions = errors[number_errors:]

        error_vector = random_error_vector(n, V.base_ring(), error_positions)
        erasure_vector = random_error_vector(n, GF(2), erasure_positions)

        message = message + error_vector

        for i in erasure_positions:
            message[i] = zero
        return message, erasure_vector
예제 #6
0
 def time_information_set_steps():
     before = process_time()
     while True:
         I = sample(range(n), k)
         Gi = G.matrix_from_columns(I)
         try:
             Gi_inv = Gi.inverse()
         except ZeroDivisionError:
             continue
         return process_time() - before
예제 #7
0
    def random_element(self):
        """
        Returns a random choice of k things from range(n).

        EXAMPLES::

            sage: from sage.combinat.choose_nk import ChooseNK
            sage: ChooseNK(5,2).random_element()
            [0, 2]
        """
        r = sorted(rnd.sample(xrange(self._n),self._k))
        return r
예제 #8
0
    def random_element(self):
        r"""
        Return a random submultiset of given length

        EXAMPLES::

            sage: Subsets(7,3).random_element()
            {1, 4, 7}
            sage: Subsets(7,5).random_element()
            {1, 3, 4, 5, 7}
        """
        return rnd.sample(self._l, self._k)
예제 #9
0
파일: subset.py 프로젝트: Etn40ff/sage
    def random_element(self):
        r"""
        Return a random submultiset of given length

        EXAMPLES::

            sage: Subsets(7,3).random_element()
            {1, 4, 7}
            sage: Subsets(7,5).random_element()
            {1, 3, 4, 5, 7}
        """
        return rnd.sample(self._l, self._k)
예제 #10
0
    def random_element(self):
        """
        Returns a random permutation of k things from range(n).

        EXAMPLES::

            sage: from sage.combinat.permutation_nk import PermutationsNK
            sage: PermutationsNK(3,2).random_element()
            [0, 1]
        """
        n, k = self._n, self._k
        rng = range(n)
        r = rnd.sample(rng, k)

        return r
예제 #11
0
    def random_element(self):
        """
        Returns a random permutation of k things from range(n).

        EXAMPLES::

            sage: from sage.combinat.permutation_nk import PermutationsNK
            sage: PermutationsNK(3,2).random_element()
            [0, 1]
        """
        n, k = self._n, self._k
        rng = range(n)
        r = rnd.sample(rng, k)

        return r
예제 #12
0
    def random_element(self):
        r"""
        Return a random submultiset of given length

        EXAMPLES::

            sage: s = Subsets(7,3).random_element()
            sage: s in Subsets(7,3)
            True

            sage: s = Subsets(7,5).random_element()
            sage: s in Subsets(7,5)
            True
        """
        return rnd.sample(self._l, self._k)
예제 #13
0
파일: split_nk.py 프로젝트: CETHop/sage
    def random_element(self):
        """
        Returns a random set partition of range(n) into a set of size k and
        a set of size n-k.

        EXAMPLES::

            sage: from sage.combinat.split_nk import SplitNK
            sage: SplitNK(5,2).random_element()
            [[0, 2], [1, 3, 4]]
        """
        r = rnd.sample(xrange(self._n),self._n)
        r0 = r[:self._k]
        r1 = r[self._k:]
        r0.sort()
        r1.sort()
        return [ r0, r1 ]
예제 #14
0
    def random_element(self):
        """
        Returns a random set partition of range(n) into a set of size k and
        a set of size n-k.

        EXAMPLES::

            sage: from sage.combinat.split_nk import SplitNK
            sage: SplitNK(5,2).random_element()
            [[0, 2], [1, 3, 4]]
        """
        r = rnd.sample(xrange(self._n),self._n)
        r0 = r[:self._k]
        r1 = r[self._k:]
        r0.sort()
        r1.sort()
        return [ r0, r1 ]
예제 #15
0
    def transmit_unsafe(self, message):
        r"""
        Returns ``message`` with as many errors as ``self._number_errors`` in it.

        If ``self._number_errors`` was passed as a tuple for the number of errors, it will
        pick a random integer between the bounds of the tuple and use it as the number of errors.

        This method does not check if ``message`` belongs to the input space of``self``.

        INPUT:

        - ``message`` -- a vector

        OUTPUT:

        - a vector of the output space

        EXAMPLES::

            sage: F = GF(59)^6
            sage: n_err = 2
            sage: Chan = channels.StaticErrorRateChannel(F, n_err)
            sage: msg = F((4, 8, 15, 16, 23, 42))
            sage: set_random_seed(10)
            sage: Chan.transmit_unsafe(msg)
            (4, 8, 4, 16, 23, 53)

        This checks that :trac:`19863` is fixed::

            sage: V = VectorSpace(GF(2), 1000)
            sage: Chan = channels.StaticErrorRateChannel(V, 367)
            sage: c = V.random_element()
            sage: (c - Chan(c)).hamming_weight()
            367
        """
        w = copy(message)
        number_errors = randint(*self.number_errors())
        V = self.input_space()
        R = V.base_ring()
        for i in sample(range(V.dimension()), number_errors):
            err = R.random_element()
            while (w[i] == err):
                err = R.random_element()
            w[i] = err
        return w
예제 #16
0
    def transmit_unsafe(self, message):
        r"""
        Returns ``message`` with as many errors as ``self._number_errors`` in it.

        If ``self._number_errors`` was passed as a tuple for the number of errors, it will
        pick a random integer between the bounds of the tuple and use it as the number of errors.

        This method does not check if ``message`` belongs to the input space of``self``.

        INPUT:

        - ``message`` -- a vector

        OUTPUT:

        - a vector of the output space

        EXAMPLES::

            sage: F = GF(59)^6
            sage: n_err = 2
            sage: Chan = channels.StaticErrorRateChannel(F, n_err)
            sage: msg = F((4, 8, 15, 16, 23, 42))
            sage: set_random_seed(10)
            sage: Chan.transmit_unsafe(msg)
            (4, 8, 4, 16, 23, 53)

        This checks that :trac:`19863` is fixed::

            sage: V = VectorSpace(GF(2), 1000)
            sage: Chan = channels.StaticErrorRateChannel(V, 367)
            sage: c = V.random_element()
            sage: (c - Chan(c)).hamming_weight()
            367
        """
        w = copy(message)
        number_errors = randint(*self.number_errors())
        V = self.input_space()
        R = V.base_ring()
        for i in sample(range(V.dimension()), number_errors):
            err = R.random_element()
            while (w[i] == err):
                err = R.random_element()
            w[i] = err
        return w
예제 #17
0
def random_partial_injection(n):
    r"""
    Return a uniformly chosen random partial injection on 0, 1, ..., n-1.

    INPUT:

    - ``n`` -- integer

    OUTPUT:

        list

    EXAMPLES::

        sage: from slabbe import random_partial_injection
        sage: random_partial_injection(10)
        [3, 5, 2, None, 1, None, 0, 8, 7, 6]
        sage: random_partial_injection(10)
        [1, 7, 4, 8, 3, 5, 9, None, 6, None]
        sage: random_partial_injection(10)
        [5, 6, 8, None, 7, 4, 0, 9, None, None]

    TODO::

        Adapt the code once this is merged:

        https://trac.sagemath.org/ticket/24416

    AUTHORS:

    - Sébastien Labbé and Vincent Delecroix, Nov 30, 2017, Sage Thursdays
      at LaBRI
    """
    L = number_of_partial_injection(n)
    s = sum(L).n()
    L = [a/s for a in L]   # because of the bug #24416
    X = GeneralDiscreteDistribution(L)
    k = X.get_random_element()
    codomain = sample(range(n), k)
    missing = [None]*(n-k)
    codomain.extend(missing)
    shuffle(codomain)
    return codomain
예제 #18
0
    def random_element(self):
        """
        Returns a random element of the class of subsets of s of size k (in
        other words, a random subset of s of size k).

        EXAMPLES::

            sage: Subsets(3, 2).random_element()
            {1, 2}
            sage: Subsets(3,4).random_element()
            Traceback (most recent call last):
            ...
            EmptySetError
        """
        lset = self._ls

        if self._k > len(lset):
            raise EmptySetError
        else:
            return self.element_class(rnd.sample(lset, self._k))
예제 #19
0
파일: subset.py 프로젝트: Etn40ff/sage
    def random_element(self):
        """
        Returns a random element of the class of subsets of s of size k (in
        other words, a random subset of s of size k).

        EXAMPLES::

            sage: Subsets(3, 2).random_element()
            {1, 2}
            sage: Subsets(3,4).random_element()
            Traceback (most recent call last):
            ...
            EmptySetError
        """
        lset = self._ls

        if self._k > len(lset):
            raise EmptySetError
        else:
            return self.element_class(rnd.sample(lset, self._k))
예제 #20
0
파일: subword.py 프로젝트: mcognetta/sage
    def random_element(self):
        r"""
        Return a random subword of given length with uniform law.

        EXAMPLES::

            sage: S1 = Subwords([1,2,3,2,1],3)
            sage: S2 = Subwords([4,4,5,5,4,5,4,4],3)
            sage: for i in range(100):
            ....:   w = S1.random_element()
            ....:   if w in S2:
            ....:       assert(w == [])
            sage: for i in range(100):
            ....:   w = S2.random_element()
            ....:   if w in S1:
            ....:       assert(w == [])
        """
        sample = prandom.sample(self._w, self._k)
        if self._build is list:
            return sample
        return self._build(sample)
예제 #21
0
    def random_element(self):
        r"""
        Return a random subword of given length with uniform law.

        EXAMPLES::

            sage: S1 = Subwords([1,2,3,2,1],3)
            sage: S2 = Subwords([4,4,5,5,4,5,4,4],3)
            sage: for i in xrange(100):
            ....:   w = S1.random_element()
            ....:   if w in S2:
            ....:       assert(w == [])
            sage: for i in xrange(100):
            ....:   w = S2.random_element()
            ....:   if w in S1:
            ....:       assert(w == [])
        """
        sample = prandom.sample(self._w, self._k)
        if self._build is list:
            return sample
        return self._build(sample)
예제 #22
0
파일: tests.py 프로젝트: Etn40ff/sage
    def __init__(self, index=20, index_max=50, odd_probability=0.5):
        r"""
        Create an arithmetic subgroup testing object.

        INPUT:

        - ``index`` - the index of random subgroup to test

        - ``index_max`` - the maximum index for congruence subgroup to test

        EXAMPLES::

            sage: from sage.modular.arithgroup.tests import Test
            sage: Test()
            Arithmetic subgroup testing class
        """
        self.congroups = []
        i = 1
        self.odd_probability = odd_probability
        if index%2:
            self.odd_probability=0
        while Gamma(i).index() < index_max:
            self.congroups.append(Gamma(i))
            i += 1
        i = 1
        while Gamma0(i).index() < index_max:
            self.congroups.append(Gamma0(i))
            i += 1
        i = 2
        while Gamma1(i).index() < index_max:
            self.congroups.append(Gamma1(i))
            M = Zmod(i)
            U = [x for x in M if x.is_unit()]
            for j in xrange(1,len(U)-1):
                self.congroups.append(GammaH(i,prandom.sample(U,j)))
            i += 1

        self.index = index
예제 #23
0
파일: tests.py 프로젝트: yjjcc/sage
    def __init__(self, index=20, index_max=50, odd_probability=0.5):
        r"""
        Create an arithmetic subgroup testing object.

        INPUT:

        - ``index`` - the index of random subgroup to test

        - ``index_max`` - the maximum index for congruence subgroup to test

        EXAMPLES::

            sage: from sage.modular.arithgroup.tests import Test
            sage: Test()
            Arithmetic subgroup testing class
        """
        self.congroups = []
        i = 1
        self.odd_probability = odd_probability
        if index % 4:
            self.odd_probability = 0
        while Gamma(i).index() < index_max:
            self.congroups.append(Gamma(i))
            i += 1
        i = 1
        while Gamma0(i).index() < index_max:
            self.congroups.append(Gamma0(i))
            i += 1
        i = 2
        while Gamma1(i).index() < index_max:
            self.congroups.append(Gamma1(i))
            M = Zmod(i)
            U = [x for x in M if x.is_unit()]
            for j in range(1, len(U) - 1):
                self.congroups.append(GammaH(i, prandom.sample(U, j)))
            i += 1

        self.index = index
예제 #24
0
    def UniformRandomUniform(self, n, k, m):
        r"""
        Return a uniformly sampled `k`-uniform hypergraph on `n` points with
        `m` hyperedges.

        - ``n`` -- number of nodes of the graph

        - ``k`` -- uniformity

        - ``m`` -- number of edges

        EXAMPLES::

            sage: H = hypergraphs.UniformRandomUniform(52, 3, 17)
            sage: H
            Incidence structure with 52 points and 17 blocks
            sage: H.is_connected()
            False

        TESTS::

            sage: hypergraphs.UniformRandomUniform(-52, 3, 17)
            Traceback (most recent call last):
            ...
            ValueError: number of vertices should be non-negative
            sage: hypergraphs.UniformRandomUniform(52.9, 3, 17)
            Traceback (most recent call last):
            ...
            ValueError: number of vertices should be an integer
            sage: hypergraphs.UniformRandomUniform(52, -3, 17)
            Traceback (most recent call last):
            ...
            ValueError: the uniformity should be non-negative
            sage: hypergraphs.UniformRandomUniform(52, I, 17)
            Traceback (most recent call last):
            ...
            ValueError: the uniformity should be an integer
        """
        from sage.rings.integer import Integer
        from sage.combinat.subset import Subsets
        from sage.misc.prandom import sample

        # Construct the vertex set
        if n < 0:
            raise ValueError("number of vertices should be non-negative")
        try:
            nverts = Integer(n)
        except TypeError:
            raise ValueError("number of vertices should be an integer")
        vertices = range(nverts)

        # Construct the edge set
        if k < 0:
            raise ValueError("the uniformity should be non-negative")
        try:
            uniformity = Integer(k)
        except TypeError:
            raise ValueError("the uniformity should be an integer")
        all_edges = Subsets(vertices, uniformity)
        try:
            edges = sample(all_edges, m)
        except OverflowError:
            raise OverflowError("binomial({}, {}) too large to be treated".format(n, k))
        except ValueError:
            raise ValueError("number of edges m must be between 0 and binomial({}, {})".format(n, k))

        from sage.combinat.designs.incidence_structures import IncidenceStructure
        return IncidenceStructure(points=vertices, blocks=edges)
예제 #25
0
    def UniformRandomUniform(self, n, k, m):
        r"""
        Return a uniformly sampled `k`-uniform hypergraph on `n` points with
        `m` hyperedges.

        - ``n`` -- number of nodes of the graph

        - ``k`` -- uniformity

        - ``m`` -- number of edges

        EXAMPLES::

            sage: H = hypergraphs.UniformRandomUniform(52, 3, 17)
            sage: H
            Incidence structure with 52 points and 17 blocks
            sage: H.is_connected()
            False

        TESTS::

            sage: hypergraphs.UniformRandomUniform(-52, 3, 17)
            Traceback (most recent call last):
            ...
            ValueError: number of vertices should be non-negative
            sage: hypergraphs.UniformRandomUniform(52.9, 3, 17)
            Traceback (most recent call last):
            ...
            ValueError: number of vertices should be an integer
            sage: hypergraphs.UniformRandomUniform(52, -3, 17)
            Traceback (most recent call last):
            ...
            ValueError: the uniformity should be non-negative
            sage: hypergraphs.UniformRandomUniform(52, I, 17)
            Traceback (most recent call last):
            ...
            ValueError: the uniformity should be an integer
        """
        from sage.rings.integer import Integer
        from sage.combinat.subset import Subsets
        from sage.misc.prandom import sample

        # Construct the vertex set
        if n < 0:
            raise ValueError("number of vertices should be non-negative")
        try:
            nverts = Integer(n)
        except TypeError:
            raise ValueError("number of vertices should be an integer")
        vertices = range(nverts)

        # Construct the edge set
        if k < 0:
            raise ValueError("the uniformity should be non-negative")
        try:
            uniformity = Integer(k)
        except TypeError:
            raise ValueError("the uniformity should be an integer")
        all_edges = Subsets(vertices, uniformity)
        try:
            edges = sample(all_edges, m)
        except OverflowError:
            raise OverflowError(
                "binomial({}, {}) too large to be treated".format(n, k))
        except ValueError:
            raise ValueError(
                "number of edges m must be between 0 and binomial({}, {})".
                format(n, k))

        from sage.combinat.designs.incidence_structures import IncidenceStructure
        return IncidenceStructure(points=vertices, blocks=edges)
예제 #26
0
    def decode(self, r):
        r"""
        The Lee-Brickell algorithm as described in the class doc.

        Note that either parameters must be given at construction time or
        :meth:`sage.coding.information_set_decoder.InformationSetAlgorithm.calibrate()`
        should be called before calling this method.

        INPUT:

        - `r` -- a received word, i.e. a vector in the ambient space of
          :meth:`decoder.Decoder.code`.

        OUTPUT: A codeword whose distance to `r` satisfies ``self.decoding_interval()``.

        EXAMPLES::

            sage: M = matrix(GF(2), [[1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0],\
                                     [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1],\
                                     [0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0],\
                                     [0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1],\
                                     [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1]])
            sage: C = codes.LinearCode(M)
            sage: from sage.coding.information_set_decoder import LeeBrickellISDAlgorithm
            sage: A = LeeBrickellISDAlgorithm(C, (2,2))
            sage: c = C.random_element()
            sage: Chan = channels.StaticErrorRateChannel(C.ambient_space(), 2)
            sage: r = Chan(c)
            sage: c_out = A.decode(r)
            sage: (r - c).hamming_weight() == 2
            True
        """
        import itertools
        from sage.misc.prandom import sample
        C = self.code()
        n, k = C.length(), C.dimension()
        tau = self.decoding_interval()
        p = self.parameters()['search_size']
        F = C.base_ring()
        G = C.generator_matrix()
        Fstar = F.list()[1:]
        while True:
            # step 1.
            I = sample(range(n), k)
            Gi = G.matrix_from_columns(I)
            try:
                Gi_inv = Gi.inverse()
            except ZeroDivisionError:
                # I was not an information set
                continue
            Gt = Gi_inv * G
            #step 2.
            y = r - vector([r[i] for i in I]) * Gt
            g = Gt.rows()
            #step 3.
            for pi in range(p + 1):
                for A in itertools.combinations(range(k), pi):
                    for m in itertools.product(Fstar, repeat=pi):
                        e = y - sum(m[i] * g[A[i]] for i in range(pi))
                        errs = e.hamming_weight()
                        if errs >= tau[0] and errs <= tau[1]:
                            return r - e