| 272 | | return self._hash() |
|---|
| 273 | | |
|---|
| | 288 | if not self._mutability._is_immutable: |
|---|
| | 289 | raise TypeError, "mutable matrices are unhashable" |
|---|
| | 290 | |
|---|
| | 291 | x = self.fetch('hash') |
|---|
| | 292 | if not x is None: |
|---|
| | 293 | return x |
|---|
| | 294 | |
|---|
| | 295 | if self._nrows == 0 or self._ncols == 0: |
|---|
| | 296 | return 0 |
|---|
| | 297 | |
|---|
| | 298 | cdef unsigned long i, j, truerow |
|---|
| | 299 | cdef unsigned long start, shift |
|---|
| | 300 | cdef word row_xor |
|---|
| | 301 | cdef word end_mask = ~(((<word>1)<<(RADIX - self._ncols%RADIX))-1) |
|---|
| | 302 | cdef word top_mask, bot_mask |
|---|
| | 303 | cdef word cur |
|---|
| | 304 | cdef word* row |
|---|
| | 305 | |
|---|
| | 306 | # running_xor is the xor of all words in the matrix, as if the rows |
|---|
| | 307 | # in the matrix were written out consecutively, without regard to |
|---|
| | 308 | # word boundaries. |
|---|
| | 309 | cdef word running_xor = 0 |
|---|
| | 310 | # running_parity is the number of extra words that must be xor'd. |
|---|
| | 311 | cdef unsigned long running_parity = 0 |
|---|
| | 312 | |
|---|
| | 313 | |
|---|
| | 314 | for i from 0 <= i < self._entries.nrows: |
|---|
| | 315 | |
|---|
| | 316 | # All this shifting and masking os because the |
|---|
| | 317 | # rows are word-alligned. |
|---|
| | 318 | truerow = self._entries.rowswap[i] |
|---|
| | 319 | row = self._entries.values + truerow |
|---|
| | 320 | start = (i*self._entries.ncols) >> 6 |
|---|
| | 321 | shift = (i*self._entries.ncols) & 0x3F |
|---|
| | 322 | bot_mask = (~(<word>0)) << shift |
|---|
| | 323 | top_mask = ~bot_mask |
|---|
| | 324 | |
|---|
| | 325 | if self._entries.width > 1: |
|---|
| | 326 | row_xor = row[0] |
|---|
| | 327 | running_parity ^= start & parity_mask(row[0] & bot_mask) |
|---|
| | 328 | |
|---|
| | 329 | for j from 1 <= j < self._entries.width - 1: |
|---|
| | 330 | row_xor ^= row[j] |
|---|
| | 331 | cur = ((row[j-1] << (63-shift)) << 1) ^ (row[j] >> shift) |
|---|
| | 332 | running_parity ^= (start+j) & parity_mask(cur) |
|---|
| | 333 | |
|---|
| | 334 | running_parity ^= (start+j) & parity_mask(row[j-1] & top_mask) |
|---|
| | 335 | |
|---|
| | 336 | else: |
|---|
| | 337 | j = 0 |
|---|
| | 338 | row_xor = 0 |
|---|
| | 339 | |
|---|
| | 340 | cur = row[j] & end_mask |
|---|
| | 341 | row_xor ^= cur |
|---|
| | 342 | running_parity ^= (start+j) & parity_mask(cur & bot_mask) |
|---|
| | 343 | running_parity ^= (start+j+1) & parity_mask(cur & top_mask) |
|---|
| | 344 | |
|---|
| | 345 | start = (i*self._entries.ncols) & (RADIX-1) |
|---|
| | 346 | running_xor ^= (row_xor >> start) ^ ((row_xor << (RADIX-1-start)) << 1) |
|---|
| | 347 | |
|---|
| | 348 | cdef unsigned long bit_is_set |
|---|
| | 349 | cdef unsigned long h |
|---|
| | 350 | |
|---|
| | 351 | # Now we assemble the running_parity and running_xor to get the hash. |
|---|
| | 352 | # Viewing the flattened matrix as a list of a_i, the hash is the xor |
|---|
| | 353 | # of the i for which a_i is non-zero. We split i into the lower RADIX |
|---|
| | 354 | # bits and the rest, so i = i1 << RADIX + i0. Now two matching i0 |
|---|
| | 355 | # would cancel, so we only need the parity of how many of each |
|---|
| | 356 | # possible i0 occur. This is stored in the bits of running_xor. |
|---|
| | 357 | # Similarly, running_parity is the xor of the i1 needed. It's called |
|---|
| | 358 | # parity because i1 is constant accross a word, and for each word |
|---|
| | 359 | # the number of i1 to add is equal to the number of set bits in that |
|---|
| | 360 | # word (but because two cancel, we only need keep track of the |
|---|
| | 361 | # parity. |
|---|
| | 362 | h = RADIX * running_parity |
|---|
| | 363 | for i from 0 <= i < RADIX: |
|---|
| | 364 | bit_is_set = (running_xor >> (RADIX-1-i)) & 1 |
|---|
| | 365 | h ^= (RADIX-1) & ~(bit_is_set-1) & i |
|---|
| | 366 | |
|---|
| | 367 | if h == -1: |
|---|
| | 368 | h = -2 |
|---|
| | 369 | |
|---|
| | 370 | self.cache('hash', h) |
|---|
| | 371 | return h |
|---|
| | 372 | |
|---|
| | 373 | |
|---|
| | 1325 | |
|---|
| | 1326 | |
|---|
| | 1327 | |
|---|
| | 1328 | # Used for hashing |
|---|
| | 1329 | cdef int i, k |
|---|
| | 1330 | cdef unsigned long parity_table[256] |
|---|
| | 1331 | for i from 0 <= i < 256: |
|---|
| | 1332 | parity_table[i] = 1 & ((i) ^ (i>>1) ^ (i>>2) ^ (i>>3) ^ |
|---|
| | 1333 | (i>>4) ^ (i>>5) ^ (i>>6) ^ (i>>7)) |
|---|
| | 1334 | |
|---|
| | 1335 | # gmp's ULONG_PARITY may use special |
|---|
| | 1336 | # assembly instructions, could be faster |
|---|
| | 1337 | cpdef inline unsigned long parity(word a): |
|---|
| | 1338 | """ |
|---|
| | 1339 | Returns the parity of the number of bits in a. |
|---|
| | 1340 | |
|---|
| | 1341 | EXAMPLES: |
|---|
| | 1342 | sage: from sage.matrix.matrix_mod2_dense import parity |
|---|
| | 1343 | sage: parity(1) |
|---|
| | 1344 | 1L |
|---|
| | 1345 | sage: parity(3) |
|---|
| | 1346 | 0L |
|---|
| | 1347 | sage: parity(0x10000101011) |
|---|
| | 1348 | 1L |
|---|
| | 1349 | """ |
|---|
| | 1350 | if sizeof(word) == 8: |
|---|
| | 1351 | a ^= a >> 32 |
|---|
| | 1352 | a ^= a >> 16 |
|---|
| | 1353 | a ^= a >> 8 |
|---|
| | 1354 | return parity_table[a & 0xFF] |
|---|
| | 1355 | |
|---|
| | 1356 | cdef inline unsigned long parity_mask(word a): |
|---|
| | 1357 | return -parity(a) |