Skip to content

Commit dbd778e

Browse files
author
Release Manager
committed
sagemathgh-40571: Add lattice utility functions This PR adds two lattice utility functions, namely, `gaussian_heuristic` and `hadamard_ratio`. These are useful when evaluating how good the approx CVP/SVP solutions are to the exact CVP/SVP solutions. ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> - [x] The title is concise and informative. - [x] The description explains in detail what this PR is about. - [x] I have linked a relevant issue or discussion. - [x] I have created tests covering the changes. - [x] I have updated the documentation and checked the documentation preview. URL: sagemath#40571 Reported by: Sahil Jain Reviewer(s): Sahil Jain, user202729
2 parents 5741ca3 + b4cdf87 commit dbd778e

File tree

1 file changed

+91
-0
lines changed

1 file changed

+91
-0
lines changed

src/sage/modules/free_module_integer.py

Lines changed: 91 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,90 @@ 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+
r"""
902+
Computes the normalized Hadamard ratio of the given basis.
903+
904+
The normalized Hadamard ratio of the basis `B = \left{ v_1, v_2, \dots, v_n \right}` is defined as
905+
906+
.. MATH::
907+
908+
\mathcal{H}(B) = \left( \dfrac{\det L}{\|v_1\| \|v_2\| \cdots \|v_n\|} \right)^{\frac{1}{n}}
909+
910+
The closer this ratio is to 1, the more orthogonal the basis is.
911+
912+
INPUT:
913+
914+
- ``use_reduced_basis`` -- boolean (default: ``True``); uses reduced basis for computing the ratio
915+
916+
OUTPUT: the ratio described above.
917+
918+
EXAMPLES::
919+
920+
sage: from sage.modules.free_module_integer import IntegerLattice
921+
sage: L = IntegerLattice([[101, 0, 0, 0], [0, 101, 0, 0], [0, 0, 101, 0], [-28, 39, 45, 1]], lll_reduce=False)
922+
sage: L.hadamard_ratio()
923+
4331^(1/8)*(1/4331)^(1/4)
924+
sage: float(L.hadamard_ratio()) # rel tol 1e-13
925+
0.351096481348176
926+
sage: L.LLL()
927+
[ 1 -5 2 18]
928+
[ -5 25 -10 11]
929+
[-17 -16 -34 -3]
930+
[-39 -7 23 5]
931+
sage: float(L.hadamard_ratio()) # rel tol 1e-13
932+
0.9933322263147489
933+
"""
934+
if use_reduced_basis:
935+
basis = self.reduced_basis
936+
else:
937+
basis = self.basis_matrix()
938+
939+
n = basis.nrows()
940+
r = self.rank()
941+
assert r == n
942+
943+
ratio = (self.discriminant().sqrt() / prod([v.norm() for v in basis]))**(1/r)
944+
assert 0 < ratio <= 1
945+
return ratio
946+
947+
def gaussian_heuristic(self, exact_form=False):
948+
r"""
949+
Computes the Gaussian expected shortest length, also known as the Gaussian
950+
heuristic. This estimates the expected norm of the shortest non-zero vector
951+
in the lattice. The heuristic is independent of the chosen basis.
952+
953+
INPUT:
954+
955+
- ``exact_form`` -- boolean (default: ``False``); uses exact formulation
956+
based on gamma function, instead of using stirling's approximation
957+
958+
OUTPUT: The Gaussian heuristic described above.
959+
960+
EXAMPLES::
961+
962+
sage: from sage.modules.free_module_integer import IntegerLattice
963+
sage: L = IntegerLattice([[101, 0, 0, 0], [0, 101, 0, 0], [0, 0, 101, 0], [-28, 39, 45, 1]])
964+
sage: L.gaussian_heuristic()
965+
1030301^(1/4)*sqrt(2)*e^(-1/2)/sqrt(pi)
966+
sage: float(L.gaussian_heuristic()) # rel tol 1e-13
967+
15.418206247181422
968+
969+
For small `n`, the exact and approximate forms differ significantly::
970+
971+
sage: float(L.gaussian_heuristic(exact_form=True)) # rel tol 1e-13
972+
21.375859827168494
973+
"""
974+
basis = self.basis_matrix()
975+
976+
n = basis.nrows()
977+
r = self.rank()
978+
assert r == n
979+
980+
D = self.discriminant().sqrt()
981+
982+
if exact_form:
983+
return (D * gamma(1 + (r/2)))**(1/r) / pi.sqrt()
984+
else:
985+
return D**(1/r) * (r/(2*pi*e)).sqrt()

0 commit comments

Comments
 (0)