Skip to content

Commit 62bf867

Browse files
committed
Lattice functions
1 parent 85c8f1e commit 62bf867

File tree

1 file changed

+78
-0
lines changed

1 file changed

+78
-0
lines changed

src/sage/modules/free_module_integer.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@
3737
from sage.misc.cachefunc import cached_method
3838
from sage.modules.free_module import FreeModule_submodule_with_basis_pid, FreeModule_ambient_pid
3939
from sage.modules.free_module_element import vector
40+
from math import prod
41+
from sage.functions.all import gamma
42+
from sage.symbolic.constants import pi, e
43+
4044

4145
try:
4246
from sage.rings.number_field.number_field_element import OrderElement_absolute
@@ -892,3 +896,77 @@ def babai(self, *args, **kwargs):
892896
Alias for :meth:`approximate_closest_vector`.
893897
"""
894898
return self.approximate_closest_vector(*args, **kwargs)
899+
900+
def hadamard_ratio(self, use_reduced_basis=True):
901+
"""
902+
Computes the normalized hadamard ratio. The closer this ratio is to 1,
903+
the more orthogonal the basis is.
904+
905+
INPUT:
906+
- ``use_reduced_basis`` -- boolean (default: ``True``); uses reduced basis
907+
for computing the ratio
908+
909+
OUTPUT: The normalized hadamard ratio. This ratio lies in (0, 1]
910+
911+
EXAMPLES::
912+
913+
sage: from sage.modules.free_module_integer import IntegerLattice
914+
sage: L = IntegerLattice([[101, 0, 0, 0], [0, 101, 0, 0], [0, 0, 101, 0], [-28, 39, 45, 1]], lll_reduce=False)
915+
sage: float(L.hadamard_ratio())
916+
0.351096481348176
917+
sage: L.LLL()
918+
[ 1 -5 2 18]
919+
[ -5 25 -10 11]
920+
[-17 -16 -34 -3]
921+
[-39 -7 23 5]
922+
sage: float(L.hadamard_ratio())
923+
0.9933322263147489
924+
"""
925+
if use_reduced_basis:
926+
basis = self.reduced_basis
927+
else:
928+
basis = self.basis_matrix()
929+
930+
n = basis.nrows()
931+
r = self.rank()
932+
assert r == n
933+
934+
ratio = (self.discriminant().sqrt() / prod([v.norm() for v in basis]))**(1/r)
935+
assert 0 < ratio <= 1
936+
return ratio
937+
938+
def gaussian_heuristic(self, exact_form=False):
939+
"""
940+
Computes the Gaussian expected shortest length, also known as the Gaussian
941+
heuristic. This estimates the expected norm of the shortest non-zero vector
942+
in the lattice. The heuristic is independent of the chosen basis.
943+
944+
INPUT:
945+
- ``exact_form`` -- boolean (default: ``False``); uses exact formulation
946+
based on gamma function, instead of estimation of the gamma function
947+
948+
OUTPUT: The Gaussian heuristic described above.
949+
950+
EXAMPLES::
951+
952+
sage: from sage.modules.free_module_integer import IntegerLattice
953+
sage: L = IntegerLattice([[101, 0, 0, 0], [0, 101, 0, 0], [0, 0, 101, 0], [-28, 39, 45, 1]])
954+
sage: float(L.gaussian_heuristic())
955+
15.418206247181422
956+
957+
For small `n`, the exact and approximate forms differ significantly:
958+
sage: float(L.gaussian_heuristic(exact_form=True))
959+
21.375859827168494
960+
"""
961+
basis = self.basis_matrix()
962+
963+
n = basis.nrows()
964+
r = self.rank()
965+
assert r == n
966+
967+
D = self.discriminant().sqrt()
968+
969+
if exact_form:
970+
return (D * gamma(1 + (r/2)))**(1/r) / pi.sqrt()
971+
else:
972+
return D**(1/r) * (r/(2*pi*e)).sqrt()

0 commit comments

Comments
 (0)