SetEchoInput(true);
function MultPolFacts(f)
    if #f eq 0 then
        return Universe(f)[1]!1;
    end if;

    return &*[T[1]^(T[2]) : T in f];
end function;

function check_fact(f, m, err)
    try
	F, c := Factorization(f);
    catch e
	e`Object; //e`Position; prints e-r-r-o-r which is bad for tests
	assert not err;
	return false;
    end try;
    g := c*MultPolFacts(F) - f;
/*
CoefficientRing(f);
g, IsZero(g);
[RelativePrecision(c) : c in Coefficients(g)];
*/
    assert IsZero(g) or Maximum([RelativePrecision(c) : c in Coefficients(g)]) le Precision(CoefficientRing(f))*m;
    return true;
end function;

_<x> := PolynomialRing(Rationals());
K := NumberField(x-1 : DoLinearExtension);
P := ideal< Integers(K) | 3 >;
KP,toKP:=Completion(K,P:Precision:=77);
_<X> := PolynomialRing(KP);
f := X^3 + (29*3)*X^2 - (11840*3)*X + 17946476;
Factorization(f);

//home/claus/bla.jc
p:=3;

Z:=Integers();
PolZ<x>:=PolynomialRing(Integers());

K:=pAdicField(p);
K`DefaultPrecision:=60;

g:=x^12 + 42653766018401001875*x^11 +
292870027877363145332093750*x^10 +
1819344240515112270707665495336603515625*x^9 +
12494714946593523082272932011151635881835937500*x^8 +
20704086125963793336494421707261297571111480712890625*x^7 -
2547725311475042830361450631793768777901287353515625000000*x^6 +
154466615830163511296081412690872400700986960961341857910156250*x^5 -
459711990121534086035152464774990786225713029171168804168701171875*x^4  +
1428099281972165319291454769222729263898483039076559245586395263671875* x^3 -
1639993355272840266739952624720069393190503675171459093689918518066406250*x^2 +
1988279810624410402513946117314475717186007482759490143507719039916992187500*x -
29920762697519394231012584410640084043859037635664208210073411464691162109375;

F:=ResidueClassField(RingOfIntegers(K));
PolF:=PolynomialRing(F);
fact:=Factorization(PolF!g)[1][1];

// Unramified Extension
L:=ext<K|map<Z->PolZ|k:->PolZ!fact>>;
PolL<X>:=PolynomialRing(L);

g:=PolL!g;
check_fact(g, 1, true); //this fails.


Q3:=pAdicField(3,50);
Q3Y<y>:=PolynomialRing(Q3);
check_fact(y^8+4*y^6+6*y^4+7*y^2+9*y+13, 1, true);
L:=ext<Q3|y^4+3*y^3+6*y^2+9*y+3>;
N:=ext<L|Polynomial(L,y^2+1)>;
#Roots(Polynomial(N,y^4+3*y^3+6*y^2+9*y+3));
IsIrreducible(DefiningPolynomial(N,Q3));
check_fact(DefiningPolynomial(N,Q3), 1, true);
assert IsNormal(N,Q3);

_<x>:=PolynomialRing(Rationals());
K<u>:=NumberField(x^3-x^2+x-9);
N1:=EllipticCurve([0,0,0,0,1/4*(737*u^2 + 1462*u - 7191)]);
time RankBound(N1);

SetSeed(1);
E := EllipticCurve("35072d1"); E;
td := TwoDescent(E);
check_fact(Polynomial(pAdicRing(2 : Precision := 120), [-4745061, 3483, 9, 1]), 1, true);

Q2:=pAdicField(2,30);
Q2X<x>:=PolynomialRing(Q2);
L<alpha>:=ext<Q2|x^4+6*x^2+2>;
check_fact(MinimalPolynomial(alpha^2,Q2), 1, true);
L<a>:=LocalField(Q2,x^8+8*x^5+18);
sub<L|a^2>;
u:=15094802675783*a^7-108716864188485*2*a^6+1943198818647*2^2*a^5-18711965705527*2*a^4+25125373139535*2*a^3+6209288378379*a^2-237273529225977*2*a+4879404574353*2^4;
sub<L|u>;



R<x>:=PolynomialRing(pAdicField(2,12));
f:=x^2+3*2^9;
_,_,e:=Factorisation(f: Extensions:=true);
F:=e[1]`Extension;
Roots(f,F);
check_fact(f, 1, true);
check_fact(Polynomial(F, f), 1, true);

K:=pAdicField(17,20);
M:=Matrix(2,2,[K!1,2,3,4]);
Factorization(CharacteristicPolynomial(M));

R<x>:=PolynomialRing(pAdicField(2,1000));
f:=x^8 + 426*x^4 + 14696*x^2 - 15123;
Factorisation(f: Extensions:=true);
check_fact(f, 1, true);

K:=pAdicField(2,1000);
R<x>:=PolynomialRing(K);
Factorisation(x^8+3/4*x^4-11/2*x^2-3*2^-6: Extensions:=true);
check_fact(x^8+3/4*x^4-11/2*x^2-3*2^-6, 1, true);

R<x> := PolynomialRing(Rationals());
F := NumberField(x^4 + 2*x^3 - 7*x^2 - 8*x + 1);
LSeries(F);

//SetVerbose("RoundFour",3);
PR:=PolynomialRing;
_<x>:=PR(Integers());
f:=x^4 + 2*x^3 - 7*x^2 - 8*x + 1;
Qp:=pAdicField(2,20);
Factorization(PR(Qp)!f : Extensions);
check_fact(PR(Qp)!f, 1, true);

_<x> := PolynomialRing(Rationals()).1;
f := x^4 + 2*x^3 - 7*x^2 - 8*x + 1;
F := pAdicField(2, 100);
ff := ChangeRing(f, F);
Factorization(ff : Extensions);
check_fact(ff, 1, true);

f:=Polynomial([pAdicRing(2,60)|-240,0,208,0,-100,0,-4,0,1]);
Factorisation(f);

pol:=Polynomial(
[ 971346363895498431494508239283450365116025021/65536,
-163739496645133106988714178498720349443655/2048,
4148492963115601452508552122241919388075/4096,
-4980477420983142424428640376777788973/1024,
3493156904491105603376220705635591/512, -1489782556989457946831299194329/64,
32398122841351021538513401919/256, -25446297029681966959836991/64,
87226136214777129457485/128, 8130682236469031785/8, -86831963251486687/16,
1792160394037/4, 38339343887, 0, 142805, -676, 1 ]);
K:=NumberField(pol);
L:=LSeries(K);

K := pAdicRing(2, 100);
f := Polynomial(K, [1,1]);
gs := [Polynomial(GF(2), [1,1])];
HenselLift(f, gs);

Factorization(Polynomial(pAdicRing(3),\[1,6558,3,2,6555,3,3,6558,0,1]));

f:=Polynomial([pAdicRing(2, 20) | 108, 0, 0, 0, 0, 0, 1]);
Factorization(f: Extensions:=true); // need the vararg
check_fact(f, 1, true); 

x := PolynomialRing(Integers()).1;
f := x^20 + 8*x^18 + 97*x^16 + 318*x^14 + 1986*x^12 + 2532*x^10 -
151292*x^8 - 32686*x^6 - 942631*x^4 + 12583556*x^2 - 21253933;
v := Valuation(Discriminant(f), 11);
fp := ChangeRing(f, pAdicRing(11, 1+v));
check_fact(fp, 1, true);

Q2 := pAdicField(2, 50);
P<x> := PolynomialRing(Q2);
f := -4*x^5 - 12*x^4 + 76*x^3 + 61*x^2 + 14*x + 1;
check_fact(f, 1, true);

Q2 := pAdicField(2, 50);
P<x> := PolynomialRing(Q2);
f := -4*x^5 - 12*x^4 + 76*x^3 + 61*x^2 + 14*x + 1;
check_fact(f, 1, true);

_<x> := PolynomialRing(Integers());
f:=x^28 - 20*x^27 + 138*x^26 - 252*x^25 - 745*x^24 + 4864*x^23 - 
       10688*x^22 + 900*x^21 + 64119*x^20 - 195660*x^19 + 
       329802*x^18 - 432508*x^17 + 591807*x^16 - 901604*x^15 +
       1346326*x^14 - 1781540*x^13 + 1976578*x^12 - 1806388*x^11 +
       1366474*x^10 - 830284*x^9 + 341412*x^8 - 26204*x^7 - 
       71616*x^6 + 41744*x^5 - 1735*x^4 - 8216*x^3 + 4064*x^2 -
       832*x + 64;
Qp:=pAdicField(2,80);
//check_fact(Polynomial(Qp,f));
Qp:=pAdicField(2,1000);
check_fact(Polynomial(Qp,f), 1, true);

R := pAdicRing(2,256);
P<X> := PolynomialRing(R);
check_fact((X-4)^2*(X^2-2)+2^108, 1, true);

R := pAdicRing(2,128);
P<X> := PolynomialRing(R);
check_fact((X-4)^2*(X^2-2)+2^108, 1, true);

R := pAdicRing(3,200);
P<x> := PolynomialRing(R);
check_fact((x-1)^2*(x+1), 1, true);

R := pAdicRing(5,200);
P<x> := PolynomialRing(R);
check_fact((x+2)^2*(x+1), 1, true);
check_fact((x-2)^2*(x+1), 1, true);
check_fact((x+2)^2, 1, true);
check_fact((x-2)^2, 1, true);

p := 65537;
R := pAdicRing(p,200);
P<x> := PolynomialRing(R);
check_fact((x+2)^2*(x+1), 1, true);
check_fact((x-2)^2*(x+1), 1, true);
R401 := pAdicRing(65537, 401);
P401<x401> := PolynomialRing(R401);
check_fact(P401!PolynomialRing(Integers())!((x-2)^2*(x+1)), 1, true);

_<x> := PolynomialRing(Integers());
Zp := pAdicRing(5, 40);
L<a> := ext<Zp | 2>;
L<b> := ext<L | x^2 + 5*x + 5>;
R<x> := PolynomialRing(L);
f := (x - 1)^3*(x - b)^2*(x - b^2 + b - 1);
check_fact(f, 1, true);

R := pAdicRing(2);
P<x> := PolynomialRing(R);
f := (x+1)*(x+3) + (x^2+x+1)*O(R!2^3);
g := (x+5)*(x+7) + (x^2+x+1)*O(R!2^3);
check_fact(f, 1, true);
check_fact(g, 1, true);
check_fact((x-2)^2, 1, true);
check_fact((x-2)*(x+(2^20-2)), 1, true);
check_fact((x-2)*(x+(2^19-2)), 1, true);
check_fact(-(x-2)^2, 1, true);
check_fact((x+2)*(x+(2^19+2) + O(R!2^20)), 1, true); // (Hangs)

R<x>:=PolynomialRing(pAdicField(2));
f:=x^2-5*x-2;
check_fact(f, 1, true);

R := pAdicRing(7);
P<x> := PolynomialRing(R);
check_fact((x-2)*(x+1), 1, true);
check_fact((x-2)^2*(x+1), 1, true);
check_fact((x-2)^3*(x+1), 1, true);
check_fact((x-2)^4*(x+1), 1, true);

PR<y>:=PolynomialAlgebra(pAdicRing(2,64));
PF<z>:=PolynomialAlgebra(pAdicField(2,64));
p1:=1+2*z+z^2;
check_fact(p1, 1, true);
p2:=1+2*y+y^2;
check_fact(p2, 1, true);
p3:=1+z+2*z^2;
check_fact(p3, 1, true);

R<p>:=pAdicRing(17);
Mat:=MatrixAlgebra(R,2);
A:=Mat![493150475962283123428701 + O(p^20), O(p^20), \
(p^20),493150475962283123428701 + O(p^20)];
f:=CharacteristicPolynomial(A);
check_fact(f, 1, true);

R<x>:=PolynomialRing(pAdicRing(19));
f := x^10 - 58*x^9 + 397*x^8 + 18472*x^7 - 100144*x^6 - 1664768*x^5
  + 6414100*x^4 + 46989392*x^3 - 97551152*x^2 - 319034496*x + 615833856;
check_fact(f, 1, true);

R<x> := PolynomialRing(Integers());
f := x^10 - 58*x^9 + 397*x^8 + 18472*x^7 - 100144*x^6 - 1664768*x^5 +
6414100*x^4 + 46989392*x^3 - 97551152*x^2 - 319034496*x + 615833856;
check_fact(f, 1, true);
ff := x^3 - 90*x + 188;                                                        
check_fact(ff, 1, true);
h := f div (x - 33);
check_fact(h, 1, true);
h := f* (x-33);
check_fact(h, 1, true);
h := f* (x-33)^2;
check_fact(h, 1, true);
h := f* (x-33)^3;
check_fact(h, 1, true);

/*
Not over inexact fields anymore
M:=ModularSymbols(11,2, pAdicField(5));
F<p>:=BaseField(M);
f:=CharacteristicPolynomial(HeckeOperator(M,2));
check_fact(f);
*/

P<y> := PolynomialRing(Integers());
Zp := pAdicRing(5, 40);
L<a> := ext<Zp | 2>;
L<b> := ext<L | y^2 + 5*y + 5>;
R<x> := PolynomialRing(L);
f := (x - 1)^3*(x - b)^2*(x - b^2 + b - 1);
check_fact(f, 1, true);

R := pAdicRing(3, 100);
P<X> := PolynomialRing(R);
L := ext<R | X^2-6>;
Q<T> := PolynomialRing(L);
check_fact(Q!CyclotomicPolynomial(3), 1, true);

R := pAdicRing(2, 100);
P<X> := PolynomialRing(R);
// The ramified extension defined by X^2+5, converted to an
// Eisenstein polynomial:
L := ext<R | X^2+2*X+6>;
Q<T> := PolynomialRing(L);
check_fact(Q!CyclotomicPolynomial(4), 1, true);

F := pAdicField(2);
P<X> := PolynomialRing(F);
check_fact(X^4+12*X^2+16, 1, true);

Q2 := pAdicField(2);
R<t> := PolynomialRing(Q2);
check_fact(t^31-1, 1, true);

f := X^4 + 35116431215195436211928*X^2 -
30614142422570751368837280229623196474368000;
check_fact(PolynomialRing(pAdicRing(2))!f, 1, true);

Prec := 30;
LF := function(P)
  O := Order(P);
  f := InertiaDegree(P);
  e := RamificationDegree(P);
  p := MinimalInteger(P);

  Qf := ext<pAdicRing(p, Prec) | f>;

  F := MinimalPolynomial(UniformizingElement(P));
  F := Factorisation(PolynomialRing(Qf)!F);
  i := 1;
  while not IsEisenstein(F[i][1]) do
    i := i+1;
  end while;
  F := F[i][1];
  F;
  Qfe := ext<Qf | F>;
  F := Factorisation(PolynomialRing(Qfe)! DefiningPolynomial(O));
  F;
  F := - Eltseq(F[1][1])[1];
  return Qfe, hom<O -> Qfe | F>;
end function;

M := MaximalOrder(Polynomial([-15, 0, 0, 0, 0, 0, 1]));
P2 := Decomposition(M, 2);
P3 := Decomposition(M, 3);

LF(P2[1][1]); // crashed in the p-adic factorisation
LF(P3[1][1]); // produced an empty factorisation and therefore crash in the

Q3 := pAdicField(3,60);
Q3x<x> := PolynomialAlgebra(Q3);
K := UnramifiedExtension(Q3,x^2+1);
Ky<y> := PolynomialAlgebra(K);
Phi :=  (y^5+K.1+3)*(y^10+2*K.1+9*y)*(y^5+K.1);
check_fact(Phi, 1, true);

R<x> := PolynomialRing(pAdicField(3));
check_fact(x^2+1, 1, true);

_<x> := PolynomialRing(Rationals());
check_fact(Polynomial(pAdicRing(2, 50), x^2 + 121804843573*x - 121089399256), 1, true);
check_fact(Polynomial(pAdicRing(2, 40), x^2 + 121804843573*x - 121089399256), 1, true);

pol := 4*x^3 - 3*x^2 + 268291620*x - 9603307941516;
check_fact(Polynomial(pAdicRing(2,50), pol), 1, true);
check_fact(Polynomial(pAdicRing(2,40), pol), 1, true);

_<x> := PolynomialRing(Rationals());
K := NumberField(x-1 : DoLinearExtension);
P := ideal< Integers(K) | 3 >;
KP,toKP:=Completion(K,P:Precision:=77);
_<X> := PolynomialRing(KP);
f := X^3 + (29*3)*X^2 - (11840*3)*X + 17946476;
check_fact(f, 1, true);

K := NumberField(x^8 - x^7 - 7*x^6 - 28*x^5 - 70*x^4
                     - 112*x^3 - 112*x^2 - 64*x + 1);
OK := Integers(K);
P := ideal< OK | [[3,0,0,0,0,0,0,0], [2,1,2,1,0,0,2,0]]>;
KP,toKP:=MyCompletion(P);  KP`DefaultPrecision:=74;
_<X> := PolynomialRing(KP);
f := (1 + O(KP!3^74))*X^4
  + (18418784990281203491301209762619*KP.1 -
     37453108177054226611858296122782 + O(KP!3^67))*X^3
  + ((-51294849707651635771323049791*KP.1 -
       153884549122954907313969149305)*3 + O(KP!3^67))*X^2
  + (-20525807773529186807321689691700*KP.1 +
      31132039827310276663796856347759 + O(KP!3^67))*X
  + -30031090750381804422601393453635*KP.1 +
      2616190896752423817957745105378 + O(KP!3^67);
check_fact(f, 1, true);

Z:=Integers();
PolZ<x>:=PolynomialRing(Integers());

K:=pAdicField(3);
K`DefaultPrecision:=60;

g:=x^12 + 42653766018401001875*x^11 +
292870027877363145332093750*x^10 +
1819344240515112270707665495336603515625*x^9 +
12494714946593523082272932011151635881835937500*x^8 +
20704086125963793336494421707261297571111480712890625*x^7 -
2547725311475042830361450631793768777901287353515625000000*x^6 +
154466615830163511296081412690872400700986960961341857910156250*x^5 -
459711990121534086035152464774990786225713029171168804168701171875*x^4  +
1428099281972165319291454769222729263898483039076559245586395263671875* x^3 -
1639993355272840266739952624720069393190503675171459093689918518066406250*x^2 +
1988279810624410402513946117314475717186007482759490143507719039916992187500*x -
29920762697519394231012584410640084043859037635664208210073411464691162109375;

F:=ResidueClassField(RingOfIntegers(K));
PolF:=PolynomialRing(F);
check_fact(PolF!g, 1, true);


R<x> := PolynomialRing(Integers());
k := AbsoluteField(NumberField([x^2-128*243, x^2-7^7*2^12, x^2-11^11*13]));
e := GeneralisedEquationOrder(k);
m := SmithForm(TraceMatrix(e));
mo := m[7][7]*m[8][8];
Q2 := pAdicField(2, 2*Valuation(mo, 2)+1);
check_fact(PolynomialRing(Q2)!DefiningPolynomial(k), 1, true);

K := NumberField(x^8 + 2*x^7 - 14*x^6 + 70*x^4 - 154*x^3 +
70*x^2 + 164*x - 155);
P := Decomposition(K,2)[2][1];
KP := Completion(K,P);
KPxx<xx> := PolynomialRing(KP);
pol := (1 + O(KP.1^91))*xx^3 + ((330*KP.1^6 + 156*KP.1^5 - 265*KP.1^4 -
4*KP.1^3 - 6*KP.1^2 + 638*KP.1 + 265)*KP.1^-14 + O(KP.1^63))*xx^2 +
((9*KP.1^6 + 9*KP.1^5 - 9*KP.1^4 - 9*KP.1^2 + 18*KP.1
+ 9)*KP.1^-7 + O(KP.1^77))*xx +
(602*KP.1^6 + 508*KP.1^5 - 49*KP.1^4 + 92*KP.1^3 + 138*KP.1^2
- 338*KP.1 + 49)*KP.1^-14 + O(KP.1^63);
check_fact(pol, 1, true);

R<x> := PolynomialRing(Rationals());
K := NumberField(x^8 - 3*x^7 + 14*x^4 - 14*x^2 - 10*x + 2);
P := ideal< Integers(K) | [2, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0] >;
KP, toKP := MyCompletion(P); KP`DefaultPrecision:=100;
E := EllipticCurve(toKP([0,5/4,0,-19/2,-39/4]));
Factorization(DivisionPolynomial(E,2));

_<T>:=PolynomialRing(Rationals());
f :=2*T^6 + 3*T^5 - 8*T^4 + T^3 + 7*T^2 - 6*T + 1;
Factorization(f,pAdicField(2));
check_fact(Polynomial(pAdicField(2), f), 1, true);


_<x>:=PolynomialRing(pAdicRing(2,40));
check_fact(x^8-60*x^4+224*x^2-300, 1, true);

_<x>:=PolynomialRing(Integers());
f:=x^8+16;
K:=NumberField(f);
P:=Ideal(Decomposition(K,2)[1,1]);
KP:=Completion(K,P);
KP`DefaultPrecision := 160;
check_fact(Polynomial(KP, DefiningPolynomial(KP)^2), 1, true);

pol := 4*x^3 - 3*x^2 + 268291620*x - 9603307941516;
check_fact(Polynomial(pAdicRing(2,10), pol), 1, true);
//check_fact(Polynomial(pAdicRing(2,5), pol));

f := x^24 - 144*x^22 - 8*x^21 + 8100*x^20 + 648*x^19 - 234876*x^18 -
26136*x^17 + 3886902*x^16 + 560848*x^15 - 38183556*x^14 -
6367536*x^13 + 223904154*x^12 +
38065224*x^11 - 768917508*x^10 - 116202800*x^9 + 1488473181*x^8 +
166836600*x^7 - 1552731608*x^6 - 112549200*x^5 + 810948870*x^4 +
25229888*x^3 - 174956700*x^2 + 3959448*x + 7784369;
L2 := pAdicField(2);
L2`DefaultPrecision := 500;
L2x := PolynomialRing(L2);
check_fact(L2x !f, 1, true);

check_fact(Polynomial([pAdicField(2,70) | 2^18, 0, 3*2^10, 0, 1]), 1, true);


Q2:=pAdicField(2,40);
Q2x<x>:=PolynomialRing(Q2);
f:=x^8+20*x^2+4;
K:=LocalField(Q2,f);
g:=Polynomial(K,f);
check_fact(g, 2/3, true);

for p in PrimesUpTo(500) do
    F := pAdicField(p);
    f := [Random(-1000000, 1000000) : i in [1 .. Random(2, 20)]];
    while not check_fact(Polynomial(F, f), 1, false) do
	F`DefaultPrecision *:= 2;
    end while;
end for;

for p in PrimesUpTo(500) do //[2, 3, 5, 7, 11, NextPrime(20), NextPrime(30), NextPrime(40), NextPrime(50), NextPrime(75), NextPrime(101), NextPrime(1001)] do
    F := pAdicField(p);
    f := Polynomial([Random(-100000, 100000) : i in [1 .. Random(2, 20)]]);
    for i in [1 .. Random(2, 10)] do
	f *:= Polynomial([Random(-100000, 100000) : i in [1 .. Random(2, 10)]]);
    end for;
    while not check_fact(Polynomial(F, f), 1, false) do
	F`DefaultPrecision *:= 2;
    end while;
end for;    

for p in PrimesUpTo(500) do //[2, 3, 5, 7, 11, NextPrime(20), NextPrime(30), NextPrime(40), NextPrime(50), NextPrime(75), NextPrime(101), NextPrime(1001)] do
    F := pAdicField(p);
    f := Polynomial([Random(-100000, 100000) : i in [1 .. Random(2, 20)]]);
    for i in [1 .. Random(2, 10)] do
	f *:= Polynomial([Random(-10000, 10000) : i in [1 .. Random(2, 10)]])^Random(1, 3);
    end for;
    while not check_fact(Polynomial(F, f), 1, false) do
	F`DefaultPrecision *:= 2;
    end while;
end for;

/*
too long : moved to long tests
SetVerbose("Selmer",1); //SetVerbose("EtaleAlg",1);
SetClassGroupBounds("GRH");
R<x> := PolynomialRing(Rationals());
E := EllipticCurve(CremonaDatabase(),"15a2");
done := 0;
while done lt 1 do
EE := Random(CremonaDatabase());
if Conductor(EE) gt 15 then print "\n   EE
is ", EE, "\n";
pol7 := DivisionPolynomial(EE,7); if not IsIrreducible(pol7) then
continue; end if;
F1 := Subfields(NumberField(pol7))[2][1]; assert Degree(F1) eq 8;
F1 := OptimizedRepresentation(F1);
Sel2F1 := TwoSelmerGroup( BaseChange(E,F1) ); // :
done +:= 1;
end if; 
end while;

*/
