Coverage for src\pqlattice\random\_lattice.py: 100%
24 statements
« prev ^ index » next coverage.py v7.11.0, created at 2026-01-11 23:45 +0100
« prev ^ index » next coverage.py v7.11.0, created at 2026-01-11 23:45 +0100
1import random
3import numpy as np
5from .._utils import as_integer, zeros_mat
6from ..typing import SquareMatrix
9def _gen_unimodular(n: int, rounds: int, rng: random.Random) -> SquareMatrix:
10 U = as_integer(np.eye(n))
11 for _ in range(rounds):
12 i, j = rng.sample(range(n), 2)
13 coeff = rng.sample([-1, 1], 1)
15 U[i] += coeff * U[j]
17 return U
20def randlattice(n: int, det_upper_bound: int | None = None, seed: int | None = None) -> SquareMatrix:
21 """
22 Generates lattice basis by, first generating random square matrix in Hermite normal form and then by transforming it using random unimodular matrix.
24 Parameters
25 ----------
26 n : int
27 lattice's rank
28 det_upper_bound : int | None, optional
29 upper bound of lattice volume, by default 2 ** n
30 seed : int | None, optional
31 seed for random number generator
33 Returns
34 -------
35 SquareMatrix
36 n x n matrix representing lattice basis
37 """
38 det_ub: int = 2**n if det_upper_bound is None else det_upper_bound
40 rng = random.Random(seed)
41 diagonals = [rng.randint(1, det_ub) for _ in range(n)]
43 H = zeros_mat(n)
44 for i in range(n):
45 H[i, i] = diagonals[i]
46 modulus = H[i, i]
47 for j in range(i + 1, n):
48 H[i, j] = rng.randint(0, modulus - 1)
50 U = _gen_unimodular(n, n * 5, rng)
52 basis = U @ H
53 return basis