|
39 | 39 |
|
40 | 40 | - Simon Brandhorst (2017-09): First created |
41 | 41 | - Paolo Menegatti (2018-03): Added IntegralLatticeDirectSum, IntegralLatticeGluing |
| 42 | +- Lorenz Panny (2024): enumeration routines for short and close vectors |
42 | 43 | """ |
43 | 44 |
|
44 | 45 | # **************************************************************************** |
@@ -1527,6 +1528,105 @@ def short_vectors(self, n, **kwargs): |
1527 | 1528 | short = q.short_vector_list_up_to_length(n, *kwargs) |
1528 | 1529 | return [[self(v * self.basis_matrix()) for v in L] for L in short] |
1529 | 1530 |
|
| 1531 | + def _fplll_enumerate(self, target=None): |
| 1532 | + r""" |
| 1533 | + Internal helper method to invoke the fplll enumeration routines. |
| 1534 | +
|
| 1535 | + EXAMPLES:: |
| 1536 | +
|
| 1537 | + sage: L = IntegralLattice('A4') |
| 1538 | + sage: t = vector([1.2, -3/11, 5.5, -9.1]) |
| 1539 | + sage: short = L.enumerate_short_vectors() # implicit doctest |
| 1540 | + sage: [next(short) for _ in range(10)] |
| 1541 | + [(0, 0, 0, 1), (0, 0, 1, 1), (0, 1, 1, 1), (1, 1, 1, 1), (0, 0, 1, 0), |
| 1542 | + (1, 1, 1, 0), (0, 1, 1, 0), (0, 1, 0, 0), (1, 1, 0, 0), (1, 0, 0, 0)] |
| 1543 | + sage: close = L.enumerate_close_vectors(t) # implicit doctest |
| 1544 | + sage: [next(close) for _ in range(10)] |
| 1545 | + [(1, 0, 6, -9), (1, -1, 5, -9), (2, 0, 6, -9), (1, 0, 5, -9), (1, -1, 5, -10), |
| 1546 | + (2, 1, 6, -9), (1, 0, 5, -10), (2, 0, 5, -9), (1, 0, 6, -8), (1, -1, 6, -9)] |
| 1547 | + """ |
| 1548 | + L = self.LLL() |
| 1549 | + dim = L.dimension() |
| 1550 | + gram = L.gram_matrix() |
| 1551 | + basis = L.basis_matrix() |
| 1552 | + |
| 1553 | + import fpylll |
| 1554 | + gmat = fpylll.IntegerMatrix(dim, dim) |
| 1555 | + for i in range(dim): |
| 1556 | + for j in range(dim): |
| 1557 | + gmat[i,j] = gram[i,j] |
| 1558 | + gso = fpylll.GSO.Mat(gmat, gram=True) |
| 1559 | + ok = gso.update_gso() |
| 1560 | + assert ok |
| 1561 | + |
| 1562 | + coord = None |
| 1563 | + if target is not None: |
| 1564 | + coord = basis.solve_left(target) |
| 1565 | + Mu = 1 + matrix([gso.get_mu(i,j) for j in range(dim)] for i in range(dim)) |
| 1566 | + coord *= Mu |
| 1567 | + |
| 1568 | + count = 8 |
| 1569 | + bound = gso.get_r(dim-1, dim-1) |
| 1570 | + seen = set() |
| 1571 | + while True: |
| 1572 | + enum = fpylll.Enumeration(gso, count, fpylll.EvaluatorStrategy.BEST_N_SOLUTIONS) |
| 1573 | + try: |
| 1574 | + combs = enum.enumerate(0, dim, bound, 0, coord) |
| 1575 | + except fpylll.EnumerationError: |
| 1576 | + combs = [] |
| 1577 | + if len(combs) < count: |
| 1578 | + bound *= 2 |
| 1579 | + continue |
| 1580 | + for length,comb in combs: |
| 1581 | + vec = sum(ZZ(c)*b for c,b in zip(comb,basis)) |
| 1582 | + if tuple(vec) not in seen: |
| 1583 | + yield vec |
| 1584 | + seen.add(tuple(vec)) |
| 1585 | + count *= 2 |
| 1586 | + |
| 1587 | + def enumerate_short_vectors(self): |
| 1588 | + r""" |
| 1589 | + Return an iterator over all the vectors in this lattice (modulo sign), |
| 1590 | + starting from shorter vectors. |
| 1591 | +
|
| 1592 | + .. WARNING:: |
| 1593 | +
|
| 1594 | + The returned vectors are not necessarily ordered strictly |
| 1595 | + by length. |
| 1596 | +
|
| 1597 | + EXAMPLES:: |
| 1598 | +
|
| 1599 | + sage: L = IntegralLattice(4, [[1,2,3,4], [7,7,8,8], [1,-1,1,0]]) |
| 1600 | + sage: short = L.enumerate_short_vectors() |
| 1601 | + sage: [next(short) for _ in range(20)] |
| 1602 | + [(1, -1, 1, 0), (2, -2, 2, 0), (3, -3, 3, 0), (0, 3, 2, 4), (1, 2, 3, 4), |
| 1603 | + (4, 4, 1, 0), (3, 2, -2, -4), (3, 5, 0, 0), (4, 1, -1, -4), (-1, 4, 1, 4), |
| 1604 | + (2, 1, 4, 4), (5, 3, 2, 0), (2, 3, -3, -4), (2, 6, -1, 0), (5, 0, 0, -4), |
| 1605 | + (-2, 5, 0, 4), (4, -4, 4, 0), (6, 2, 3, 0), (1, 4, -4, -4), (3, 0, 5, 4)] |
| 1606 | + """ |
| 1607 | + yield from self._fplll_enumerate() |
| 1608 | + |
| 1609 | + def enumerate_close_vectors(self, target): |
| 1610 | + r""" |
| 1611 | + Return an iterator over all the vectors in this lattice, starting |
| 1612 | + from vectors relatively close to the given ``target`` vector. |
| 1613 | +
|
| 1614 | + .. WARNING:: |
| 1615 | +
|
| 1616 | + The returned vectors are not necessarily ordered strictly |
| 1617 | + by their distance to the target. |
| 1618 | +
|
| 1619 | + EXAMPLES:: |
| 1620 | +
|
| 1621 | + sage: L = IntegralLattice(4, [[1,2,3,4], [7,7,8,8], [1,-1,1,0]]) |
| 1622 | + sage: t = vector([1/2, -133/7, 123.44, -11]) |
| 1623 | + sage: close = L.enumerate_close_vectors(t) |
| 1624 | + sage: [next(close) for _ in range(10)] |
| 1625 | + [(1, -18, 123, 148), (2, -19, 124, 148), (0, -17, 122, 148), (3, -20, 125, 148), (-1, -16, 121, 148), |
| 1626 | + (-2, -20, 125, 152), (-2, -23, 123, 148), (4, -21, 126, 148), (-3, -22, 122, 148), (-3, -19, 124, 152)] |
| 1627 | + """ |
| 1628 | + yield from self._fplll_enumerate(target) |
| 1629 | + |
1530 | 1630 | def twist(self, s, discard_basis=False): |
1531 | 1631 | r""" |
1532 | 1632 | Return the lattice with inner product matrix scaled by ``s``. |
|
0 commit comments