Z := IntegerRing();

NT := 24;
NT := 16;

/////////////////

function ShortVecLatBasis(d: b1 := 1, k := 1, b2 := 100, UniBound := 1)
/*
Return basis matrix for dim-d lattice generated by k random short vectors
with entry bound b1 and the other random vectors having entry bound b2;
result basis is original basis "messed up" by a random unimodular matrix.
*/

    SetSeed(1);
    B := MatrixRing(Z, d)!0;
    for i := 1 to k do
	for j := 1 to d do
	  B[i, j] := Random(-b1, b1);
	end for;
    end for;
    for i := k + 1 to d do
	for j := 1 to d do
	  B[i, j] := Random(-b2, b2);
	end for;
    end for;

    U := RandomUnimodularMatrix(d, UniBound);
    B := U*B;

    return B;
end function;

/////////////////

function MultiFactorPoly(R: C := 24)
/*
Return polynomial with (2*R + 1)^2 factors, defined over CyclotomicField(C)
[default C=24].
*/

    K<z> := CyclotomicField(C);
    P<x> := PolynomialRing(K);

    /*
    The integers i and j here could be randomized for genuine challenges,
    but we choose fixed values based on R for uniformity in testing:
    */

    L := Sort([<x - i*z + j, 1>: i, j in [-R .. R]]);
    f := &*[t[1]*t[2]: t in L];
    return f, L;
end function;

/////////////////

SetEchoInput(true);

d := 200;
B := ShortVecLatBasis(d);

time L := LLL(B);
    // Delta 0.75, FP

SetNthreads(1); time L := LLL(B: Method := "Integral");
    // Delta 0.75, INT1

SetNthreads(NT); time L := LLL(B: Method := "Integral");
    // Delta 0.75, INT multi-thread

time L := LLL(B: Delta := 0.999);
    // Delta 0.999, FP

SetNthreads(1); time L := LLL(B: Method := "Integral", Delta := 0.999);
    // Delta 0.999, INT1

SetNthreads(NT); time L := LLL(B: Method := "Integral", Delta := 0.999);
    // Delta 0.999, INT multi-thread

// SetVerbose("PolyFact", 1);

R := 4;
f := MultiFactorPoly(R);

SetVanHoeijLLLIntegral(false); time L1 := Factorization(f);
    // FP method

SetVanHoeijLLLIntegral(true); SetNthreads(1); time L2 := Factorization(f);
    // INT method with 1 thread

SetVanHoeijLLLIntegral(true); SetNthreads(NT); time L3 := Factorization(f);
    // INT method with multi threads

// Check correctness in all cases:
assert #L1 eq (2*R + 1)^2;
assert &*[t[1]^t[2]: t in L1] eq f;
assert L2 eq L1 and L3 eq L1;

