def test_003_shorter_than_8_symbols_per_full_pass(self):
        punc = spinal.StridedPuncturingSchedule(2, 1)
        output = [punc.next() for i in xrange(200)]
        self.assertTrue(output == [0, 1] * 100)

        punc = spinal.StridedPuncturingSchedule(3, 1)
        output = [punc.next() for i in xrange(300)]
        self.assertTrue(output == [0, 2, 1] * 100)

        punc = spinal.StridedPuncturingSchedule(6, 2)
        output = [punc.next() for i in xrange(70)]
        self.assertTrue(output == [4, 0, 5, 2, 3, 5, 1] * 10)
    def test_001_output_7_4(self):

        STRIDED_7_4_OUTPUT = [
            4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0,
            6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6,
            2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6,
            3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5,
            1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6,
            4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0,
            6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6,
            2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6,
            3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5,
            1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6,
            4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0,
            6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6,
            2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6,
            3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5,
            1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6,
            4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0,
            6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6,
            2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6,
            3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5,
            1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6,
            4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0,
            6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6, 4, 0, 6, 6,
            2, 6, 3, 5, 1, 6, 4, 0, 6, 6, 2, 6, 3, 5, 1, 6
        ]

        punc = spinal.StridedPuncturingSchedule(7, 4)
        output_7_4 = [punc.next() for i in xrange(len(STRIDED_7_4_OUTPUT))]

        self.assertEquals(output_7_4[:20], STRIDED_7_4_OUTPUT[:20])
        self.assertTrue(output_7_4 == STRIDED_7_4_OUTPUT,
                        "Output doesn't match reference")
Пример #3
0
    def test_001_repetitions_are_correct(self):
        """
        Make sure that the stream positions output by the repetition puncturing
        schedule are indeed repetitions of the original puncturing schedule.
        """
        NUM_CODE_STEPS = 20
        TESTED_POSITIONS = 100
        NUM_REPETITION_SET = [1, 2, 3, 6]

        for numRepetitions in NUM_REPETITION_SET:
            for numLastStepSymbolsPerPass in xrange(1, 4):
                punc = spinal.StridedPuncturingSchedule(
                    NUM_CODE_STEPS, numLastStepSymbolsPerPass)
                punc2 = spinal.StridedPuncturingSchedule(
                    NUM_CODE_STEPS, numLastStepSymbolsPerPass)
                repeatedPunc = spinal.RepeatingPuncturingSchedule(
                    punc2, numRepetitions)

                indices = wireless.vectorus()

                # Run twice, once without resetting and another time after
                # resetting the puncturing schedules
                for resetIter in xrange(2):
                    punc.batchNext(TESTED_POSITIONS, indices)
                    unrepeated = list(indices)

                    repeatedPunc.batchNext(TESTED_POSITIONS * numRepetitions,
                                           indices)
                    repeated = list(indices)

                    for i in range(len(repeated)):
                        self.assertEqual(
                            repeated[i], unrepeated[i / numRepetitions],
                            "location %d in repeated schedule should match location %d in original schedule"
                            % (i, i / numRepetitions))

                    # We reset to check that the repeating puncturing schedule
                    # works well after a reset
                    punc.reset()
                    repeatedPunc.reset()
Пример #4
0
    def test_002_puncturing(self):
        """
        This test considers a scenario where several passes are generated 
            contiguously.
        We produce the sequence telling which spine value each symbol was 
            generated from, in an inefficient but straightforward way. This
            sequence is then used to check the correctness of the puncturing
            schedule implementation.
        """
        MAX_NUM_CODE_STEPS = 20
        NUM_PASSES = 20
        for numCodeSteps in xrange(1, MAX_NUM_CODE_STEPS + 1):
            for numLastStepSymbolsPerPass in xrange(3):
                codePassTransmitted = range(numCodeSteps)
                codeStepsMod4 = numCodeSteps % 4

                # the number of code steps is increased to be a multiple of 4.
                # the last code step is transmitted in the added symbols
                if codeStepsMod4 != 0:
                    codePassTransmitted += ([numCodeSteps - 1] *
                                            (4 - codeStepsMod4))

                # Also, in order to transmit more of last code step, we add
                # 4*numLastStepSymbolsPerPass of the last code step
                codePassTransmitted += ([numCodeSteps - 1] *
                                        (4 * numLastStepSymbolsPerPass))

                passes = []
                shiftMap = [1, 3, 0, 2]
                for passInd in xrange(NUM_PASSES):
                    passes += codePassTransmitted[shiftMap[passInd % 4]::4]

                numSymbolsPerPass = len(codePassTransmitted) / 4

                punc = spinal.StridedPuncturingSchedule(
                    numCodeSteps, numLastStepSymbolsPerPass)

                # Check validity of numSymbolsForCodeStep
                for passInd in xrange(0, NUM_PASSES):
                    testedPasses = passes[:(passInd + 1) * numSymbolsPerPass]
                    for step in xrange(numCodeSteps):
                        self.assertEqual(
                            punc.numSymbolsForCodeStep(passInd + 1, step),
                            testedPasses.count(step))

                # Check validity of symbolIndexInPassStream
                for ind, step in enumerate(passes):
                    symbolNumInStep = passes[:ind + 1].count(step) - 1

                    self.assertEqual(
                        punc.symbolIndexInPassStream(step, symbolNumInStep),
                        ind)
Пример #5
0
    def test_001_no_repetitions(self):

        NUM_TESTED_LOCATIONS = 500

        for modulus in xrange(1, 30):
            for numLastValueSymbols in [1, 2, 7]:
                punc = spinal.StridedPuncturingSchedule(
                    modulus, numLastValueSymbols)
                numSymbolsFullPass = modulus - 1 + numLastValueSymbols
                spineIndices = wireless.vectorus()
                proto = spinal.StridedProtocol(1, modulus,
                                               NUM_TESTED_LOCATIONS,
                                               numLastValueSymbols, 1)

                lastNumSymbols = 0

                nextNumSymbols = proto.numSymbolsNextDecode(0)
                while (nextNumSymbols != 0):
                    # How many symbols were added?
                    numAddedSymbols = nextNumSymbols - lastNumSymbols
                    self.assertNotEqual(numAddedSymbols, 0,
                                        "Protocol did not advance!")
                    if nextNumSymbols != NUM_TESTED_LOCATIONS:
                        self.assertGreaterEqual(
                            numAddedSymbols, numSymbolsFullPass / 8,
                            "Expected the number of symbols between decodes to fit the puncturing"
                        )
                        self.assertLessEqual(
                            numAddedSymbols, (numSymbolsFullPass + 7) / 8,
                            "Expected the number of symbols between decodes to fit the puncturing"
                        )

                    # Get the spine indices from the puncturing schedule
                    punc.batchNext(numAddedSymbols, spineIndices)

                    # Make sure that the sequence in spineIndices is strictly
                    # increasing
                    for i in xrange(spineIndices.size() - 1):
                        self.assertGreaterEqual(
                            spineIndices[i + 1], spineIndices[i],
                            "Expected the spine location between decodes to be a non-decreasing sequence, but location %d violates this"
                            % (lastNumSymbols + i))

                    # Advance to next protocol demand
                    proto.setResult(0, nextNumSymbols, False)
                    lastNumSymbols = nextNumSymbols
                    nextNumSymbols = proto.numSymbolsNextDecode(0)
Пример #6
0
    def test_001_passLength(self):
        """
        The puncturing schedule should return the right pass length:
        
        If number of code steps, N, is divided evenly by 4, then the length
            of the pass should be N/4 + numLastSymbolsPerPass.
        Otherwise, length of pass should be similar (but N/4 should be rounded
            up)
        """
        MAX_NUM_CODE_STEPS = 20
        for numCodeSteps in xrange(1, MAX_NUM_CODE_STEPS + 1):
            for numLastStepSymbolsPerPass in xrange(3):
                punc = spinal.StridedPuncturingSchedule(
                    numCodeSteps, numLastStepSymbolsPerPass)

                self.assertEquals(punc.numSymbolsPerPass(),
                                  ((numCodeSteps + 3) / 4) +
                                  numLastStepSymbolsPerPass)
    def test_002_output_32_2(self):
        STRIDED_32_2_OUTPUT = [
            4, 12, 20, 28, 0, 8, 16, 24, 31, 6, 14, 22, 30, 2, 10, 18, 26, 7,
            15, 23, 31, 3, 11, 19, 27, 5, 13, 21, 29, 1, 9, 17, 25, 4, 12, 20,
            28, 0, 8, 16, 24, 31, 6, 14, 22, 30, 2, 10, 18, 26, 7, 15, 23, 31,
            3, 11, 19, 27, 5, 13, 21, 29, 1, 9, 17, 25, 4, 12, 20, 28, 0, 8,
            16, 24, 31, 6, 14, 22, 30, 2, 10, 18, 26, 7, 15, 23, 31, 3, 11, 19,
            27, 5, 13, 21, 29, 1, 9, 17, 25, 4, 12, 20, 28, 0, 8, 16, 24, 31,
            6, 14, 22, 30, 2, 10, 18, 26, 7, 15, 23, 31, 3, 11, 19, 27, 5, 13,
            21, 29, 1, 9, 17, 25, 4, 12, 20, 28, 0, 8, 16, 24, 31, 6, 14, 22,
            30, 2, 10, 18, 26, 7, 15, 23, 31, 3, 11, 19, 27, 5, 13, 21, 29, 1,
            9, 17, 25, 4, 12, 20, 28, 0, 8, 16, 24, 31, 6, 14, 22, 30, 2, 10,
            18, 26, 7, 15, 23, 31, 3, 11, 19, 27, 5, 13, 21, 29, 1, 9, 17, 25,
            4, 12, 20, 28, 0, 8, 16, 24, 31, 6, 14, 22, 30, 2, 10, 18, 26, 7,
            15, 23, 31, 3, 11, 19, 27, 5, 13, 21, 29, 1, 9, 17, 25, 4, 12, 20,
            28, 0, 8, 16, 24, 31, 6, 14, 22, 30, 2, 10, 18, 26, 7, 15, 23, 31,
            3, 11, 19, 27, 5, 13, 21, 29, 1, 9, 17, 25, 4, 12, 20, 28, 0, 8,
            16, 24, 31, 6, 14, 22, 30, 2, 10, 18, 26, 7, 15, 23, 31, 3, 11, 19,
            27, 5, 13, 21, 29, 1, 9, 17, 25, 4, 12, 20, 28, 0, 8, 16, 24, 31,
            6, 14, 22, 30, 2, 10, 18, 26, 7, 15, 23, 31, 3, 11, 19, 27, 5, 13,
            21, 29, 1, 9, 17, 25, 4, 12, 20, 28, 0, 8, 16, 24, 31, 6, 14, 22,
            30, 2, 10, 18, 26, 7, 15, 23, 31, 3, 11, 19, 27, 5, 13, 21, 29, 1,
            9, 17, 25, 4, 12, 20, 28, 0, 8, 16, 24, 31, 6, 14, 22, 30, 2, 10,
            18, 26, 7, 15, 23, 31, 3, 11, 19, 27, 5, 13, 21, 29, 1, 9, 17, 25,
            4, 12, 20, 28, 0, 8, 16, 24, 31, 6, 14, 22, 30, 2, 10, 18, 26, 7,
            15, 23, 31, 3, 11, 19, 27, 5, 13, 21, 29, 1, 9, 17, 25, 4, 12, 20,
            28, 0, 8, 16, 24, 31, 6, 14, 22, 30, 2, 10, 18, 26, 7, 15, 23, 31,
            3, 11, 19, 27, 5, 13, 21, 29, 1, 9, 17, 25, 4, 12, 20, 28, 0, 8,
            16, 24, 31, 6, 14, 22, 30, 2, 10, 18, 26, 7, 15, 23, 31, 3, 11, 19,
            27, 5, 13, 21, 29, 1, 9, 17, 25, 4, 12, 20, 28, 0
        ]

        punc = spinal.StridedPuncturingSchedule(32, 2)
        output_32_2 = [punc.next() for i in xrange(len(STRIDED_32_2_OUTPUT))]

        self.assertEquals(output_32_2[:20], STRIDED_32_2_OUTPUT[:20])
        self.assertTrue(output_32_2 == STRIDED_32_2_OUTPUT,
                        "Output doesn't match reference")
Пример #8
0
    def test_001_Produces_correct_symbols(self):
        PACKET_LENGTH_BITS = 192
        NUM_PASSES = 60
        NUM_CACHED_PASSES = 30
        NUM_LAST_CODE_STEP_SYMBOLS = 2
        NUM_PACKETS = 10
        NUM_COMPARISONS = 200
        
        codeParams = spinal.reference.CodeParams(salsaNumRounds = 12,
                                         hashWordSize = 64,
                                         numBitsPerCodingStep = 4,
                                         symbolSizeBits = 10,
                                         transmittedPointPrecisionBits = 16)
        
        # get packets
        packets = [numpy.random.bytes(PACKET_LENGTH_BITS / 8) for i in xrange(NUM_PACKETS)]
        
        assert(PACKET_LENGTH_BITS % codeParams.numBitsPerCodingStep == 0)
        
        
        # decide on symbol schedule
        numCodingSteps = PACKET_LENGTH_BITS / codeParams.numBitsPerCodingStep
        numSymbolsForCodingStep = numpy.ones([numCodingSteps], dtype=numpy.uint32)
        numSymbolsForCodingStep *= NUM_PASSES
        numSymbolsForCodingStep[-1] *= NUM_LAST_CODE_STEP_SYMBOLS

        fullPassLength = numCodingSteps - 1 + NUM_LAST_CODE_STEP_SYMBOLS
        
        # uncached C++ encoder
        uncachedEncoder = spinal.SalsaEncoder(
                            codeParams.numBitsPerCodingStep,
                            numCodingSteps,
                            spinal.StridedPuncturingSchedule(numCodingSteps, 
                                                  NUM_LAST_CODE_STEP_SYMBOLS),
                            codeParams.symbolSizeBits)
        
        # cached C++ encoder
        cachedEncoder = spinal.CachedSalsaEncoder(
                            uncachedEncoder,
                            NUM_PACKETS,
                            NUM_CACHED_PASSES * fullPassLength)

        for i in xrange(NUM_PACKETS):
            cachedEncoder.setPacket(i, packets[i])
        
        for compInd in xrange(NUM_COMPARISONS):
            packetInd = random.randint(0, NUM_PACKETS-1)
            firstSymbolInd = random.randint(0, NUM_PASSES*fullPassLength - 1)
            lastSymbolInd = random.randint(firstSymbolInd, NUM_PASSES*fullPassLength - 1)
            
            # encode using uncached
            uncachedSymbols = numpy.ones([lastSymbolInd - firstSymbolInd + 1], dtype=numpy.int32) * 0x7F7F7F7F
            uncachedEncoder.encode(packets[packetInd],
                                   firstSymbolInd,
                                   lastSymbolInd,
                                   uncachedSymbols)
            
            # encode using cached
            cachedSymbols = numpy.ones([lastSymbolInd - firstSymbolInd + 1], dtype=numpy.int32) * 0x77777777
            cachedEncoder.getSymbols(packetInd, 
                                     firstSymbolInd, 
                                     lastSymbolInd, 
                                     cachedSymbols)
            
            # compare
            self.assertTrue( (uncachedSymbols == cachedSymbols).all() )
Пример #9
0
    def test_001_Punctured_Encoder(self):
        PACKET_LENGTH_BITS = 192
        NUM_PASSES = 5
        NUM_LAST_CODE_STEP_SYMBOLS = 2
        
        codeParams = spinal.reference.CodeParams(salsaNumRounds = 12,
                                         hashWordSize = 64,
                                         numBitsPerCodingStep = 4,
                                         symbolSizeBits = 10,
                                         transmittedPointPrecisionBits = 10,
                                         lookaheadDepth = 0)
        
        # get packet
        packet = numpy.random.bytes(PACKET_LENGTH_BITS / 8)
        
        assert(PACKET_LENGTH_BITS % codeParams.numBitsPerCodingStep == 0)
        
        numCodingSteps = PACKET_LENGTH_BITS / codeParams.numBitsPerCodingStep
        totalNumSymbols = (numCodingSteps - 1 + NUM_LAST_CODE_STEP_SYMBOLS) * NUM_PASSES
     
        # decide on symbol schedule
        cppSpineValueIndices = wireless.vectorus()
        for codeStep in xrange(numCodingSteps - 1):
            for i in xrange(NUM_PASSES):
                cppSpineValueIndices.push_back(codeStep)
        # For last code step
        for i in xrange(NUM_PASSES * NUM_LAST_CODE_STEP_SYMBOLS):
            cppSpineValueIndices.push_back(numCodingSteps - 1)

        
        # Make c++ encoder without puncturing
        cppEncoder = spinal.CodeFactory(
                codeParams.numBitsPerCodingStep,
                numCodingSteps,
                codeParams.symbolSizeBits) \
            .salsa().encoder()
        unpuncturedSymbols = wireless.vectorus()

        
        # Encode unpunctured with C++ encoder
        cppEncoder.setPacket(packet)
        cppEncoder.encode(cppSpineValueIndices,
                          unpuncturedSymbols)
        
        # Make puncturing schedule
        punc = spinal.StridedPuncturingSchedule(numCodingSteps,
                                                NUM_LAST_CODE_STEP_SYMBOLS)
        
        # Make encoder with puncturing
        puncturedEncoder = spinal.PuncturedEncoder(cppEncoder,
                                                   punc)
        
        # Encode with puncturing
        puncturedSymbols = wireless.vectorus()
        puncturedEncoder.setPacket(packet)
        puncturedEncoder.encode(totalNumSymbols, puncturedSymbols)
        
        # Make a dictionary from spine value to all locations that are produced
        # from that spine value
        d = {}
        punc.reset()
        for i in xrange(totalNumSymbols):
            d.setdefault(punc.next(), []).append(i)
        
        # Check the two encoders produced the same symbols (taking into account
        #    the puncturing schedule)
        for codeStep in xrange(numCodingSteps - 1):
            for i in xrange(NUM_PASSES):
                self.assertEqual(unpuncturedSymbols[codeStep * NUM_PASSES + i], 
                                 puncturedSymbols[ d[codeStep][i] ],
                                 "location %d should contain the %dth sample from spine value %d, but does not match" \
                                    % (d[codeStep][i], i, codeStep))
        # last codestep
        codeStep = (numCodingSteps - 1)
        for i in xrange(NUM_PASSES * NUM_LAST_CODE_STEP_SYMBOLS):
            self.assertEqual(unpuncturedSymbols[codeStep * NUM_PASSES + i], 
                             puncturedSymbols[ d[codeStep][i] ],
                             "location %d should contain the %dth sample from spine value %d, but does not match" \
                                % (d[codeStep][i], i, codeStep))