SetEchoInput(true);

PR<x> := PolynomialRing(Rationals());
P<y> := PolynomialRing(PR);
FR1<a> := FunctionField(y^3 + 2);
P<y> := PolynomialRing(FR1);
FR2<c> := FunctionField(y^2 - a);

F<z> := GF(13, 3);
PF<x> := PolynomialRing(F);
P<y> := PolynomialRing(PF);
FF1<b> := ext<FieldOfFractions(PF) | y^2 - x>;
P<y> := PolynomialRing(FF1);
FF2<d> := ext<FF1 | y^3 - ConstantField(FF1).1>;

EFR1F := EquationOrderFinite(FR1);
MFR1F := MaximalOrderFinite(FR1);
EFR1I := EquationOrderInfinite(FR1);
MFR1I := MaximalOrderInfinite(FR1);

EFR2F := EquationOrderFinite(FR2);
MFR2F := MaximalOrderFinite(FR2);
EFR2I := EquationOrderInfinite(FR2);
MFR2I := MaximalOrderInfinite(FR2);

EFF1F := EquationOrderFinite(FF1);
MFF1F := MaximalOrderFinite(FF1);
EFF1I := EquationOrderInfinite(FF1);
MFF1I := MaximalOrderInfinite(FF1);

EFF2F := EquationOrderFinite(FF2);
MFF2F := MaximalOrderFinite(FF2);
EFF2I := EquationOrderInfinite(FF2);
MFF2I := MaximalOrderInfinite(FF2);

assert Random(FR2, 3) in FR2;
assert Random(EFR2F, 3) in EFR2F;
assert Random(MFR2F, 3) in MFR2F;
assert Random(EFR2I, 3) in EFR2I;
assert Random(MFR2I, 3) in MFR2I;

assert Random(FF2, 3) in FF2;
assert Random(EFF2F, 3) in EFF2F;
assert Random(MFF2F, 3) in MFF2F;
assert Random(EFF2I, 3) in EFF2I;
assert Random(MFF2I, 3) in MFF2I;

assert c in EFR2F;
assert c in MFR2F;
assert 1/c in EFR2I;
assert 1/c in MFR2I;

assert d in EFF2F;
assert d in MFF2F;
assert 1/d in EFF2I;
assert 1/d in MFF2I;

assert 1/(c*PR.1) notin EFR2F;
assert 1/(c*PR.1) notin MFR2F;
assert c*PR.1 notin EFR2I;
assert c*PR.1 notin MFR2I;

assert 1/(d*PF.1) notin EFF2F;
assert 1/(d*PF.1) notin MFF2F;
assert d*PF.1 notin EFF2I;
assert d*PF.1 notin MFF2I;

assert d notin FR2;
assert c notin FF2;

assert IsDivisibleBy(c^6, c);
assert IsDivisibleBy(d^5, d);

assert IsDivisibleBy(EFR2F!c^7, EFR2F!c);
assert IsDivisibleBy(MFR2F!c^4, MFR2F!c);
assert IsDivisibleBy(EFR2I!1/c^6, EFR2I!1/c);
assert IsDivisibleBy(MFR2I!1/c^5, MFR2I!1/c);

assert IsDivisibleBy(EFF2F!d^7, EFF2F!d);
assert IsDivisibleBy(MFF2F!d^4, MFF2F!d);
assert IsDivisibleBy(EFF2I!1/d^6, EFF2I!1/d);
assert IsDivisibleBy(MFF2I!1/d^5, MFF2I!1/d);

assert IsMinusOne(FR2!-1);
assert IsMinusOne(FF2!-1);

assert IsMinusOne(EFR2F!-1);
assert IsMinusOne(MFR2F!-1);
assert IsMinusOne(EFR2I!-1);
assert IsMinusOne(MFR2I!-1);

assert IsMinusOne(EFF2F!-1);
assert IsMinusOne(MFF2F!-1);
assert IsMinusOne(EFF2I!-1);
assert IsMinusOne(MFF2I!-1);

assert not IsMinusOne(c^10);
assert not IsMinusOne(d^11);

assert not IsMinusOne(EFR2F!c^7);
assert not IsMinusOne(MFR2F!c^4);
assert not IsMinusOne(EFR2I!1/c^6);
assert not IsMinusOne(MFR2I!1/c^5);

assert not IsMinusOne(EFF2F!d^7);
assert not IsMinusOne(MFF2F!d^4);
assert not IsMinusOne(EFF2I!1/d^6);
assert not IsMinusOne(MFF2I!1/d^5);

assert not IsIdempotent(c);
assert not IsIdempotent(d);

assert not IsIdempotent(EFR2F!c);
assert not IsIdempotent(MFR2F!c);
assert not IsIdempotent(EFR2I!1/c);
assert not IsIdempotent(MFR2I!1/c);

assert not IsIdempotent(EFF2F!d);
assert not IsIdempotent(MFF2F!d);
assert not IsIdempotent(EFF2I!1/d);
assert not IsIdempotent(MFF2I!1/d);

assert IsUnit(c);
assert IsUnit(d);

assert not IsUnit(EFR2F!(c*PR.1));
assert not IsUnit(MFR2F!(c*PR.1));
assert not IsUnit(EFR2I!(1/(c*PR.1^2)));
assert not IsUnit(MFR2I!(1/(c*PR.1)));

assert not IsUnit(EFF2F!(d*PF.1));
assert not IsUnit(MFF2F!(d*PF.1));
assert not IsUnit(EFF2I!(1/(d*PF.1^2)));
assert not IsUnit(MFF2I!(1/(d*PF.1)));

assert IsSeparating(c^5*PR.1);
assert IsSeparating(d*PF.1);

assert IsConstant(c^4);
assert IsConstant(d^5);

assert not IsConstant(FR2!PR.1);
assert not IsConstant(FF2!PF.1);

assert IsConstant(EFR2F!4);
assert IsConstant(MFR2F!6);
assert IsConstant(EFR2I!10);
assert IsConstant(MFR2I!15);

assert IsConstant(EFF2F!200);
assert IsConstant(MFF2F!100);
assert IsConstant(EFF2I!38);
assert IsConstant(MFF2I!25);

ER, mr := ExactConstantField(FR2);
EF, mf := ExactConstantField(FF2);

assert DefiningPolynomial(AbsoluteField(ER)) eq 
DefiningPolynomial(ExactConstantField(RationalExtensionRepresentation(FR2)));
assert DefiningPolynomial(EF) eq 
DefiningPolynomial(ExactConstantField(RationalExtensionRepresentation(FF2)));

assert mr(ER.1) @@ mr eq ER.1;
assert mf(EF.1) @@ mf eq EF.1;

r := Random(FR2, 3);
r1, r2 := IntegralSplit(r, EFR2F);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, MFR2F);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, EFR2I);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, MFR2I);
assert r1/r2 eq r;

r := Random(FF2, 3);
r1, r2 := IntegralSplit(r, EFF2F);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, MFF2F);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, EFF2I);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, MFF2I);
assert r1/r2 eq r;

r := Random(EFR2F, 3);
r1, r2 := IntegralSplit(r, EFR2F);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, MFR2F);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, EFR2I);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, MFR2I);
assert r1/r2 eq r;

r := Random(MFR2F, 3);
r1, r2 := IntegralSplit(r, EFR2F);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, MFR2F);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, EFR2I);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, MFR2I);
assert r1/r2 eq r;

r := Random(EFR2I, 3);
r1, r2 := IntegralSplit(r, EFR2F);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, MFR2F);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, EFR2I);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, MFR2I);
assert r1/r2 eq r;

r := Random(MFR2I, 3);
r1, r2 := IntegralSplit(r, EFR2F);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, MFR2F);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, EFR2I);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, MFR2I);
assert r1/r2 eq r;

r := Random(EFF2F, 3);
r1, r2 := IntegralSplit(r, EFF2F);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, MFF2F);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, EFF2I);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, MFF2I);
assert r1/r2 eq r;

r := Random(MFF2F, 3);
r1, r2 := IntegralSplit(r, EFF2F);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, MFF2F);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, EFF2I);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, MFF2I);
assert r1/r2 eq r;

r := Random(EFF2I, 3);
r1, r2 := IntegralSplit(r, EFF2F);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, MFF2F);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, EFF2I);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, MFF2I);
assert r1/r2 eq r;

r := Random(MFF2I, 3);
r1, r2 := IntegralSplit(r, EFF2F);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, MFF2F);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, EFF2I);
assert r1/r2 eq r;
r1, r2 := IntegralSplit(r, MFF2I);
assert r1/r2 eq r;

r := Random(FR2, 4);
assert Numerator(r, EFR2F)/Denominator(r, EFR2F) eq r;
assert Numerator(r, MFR2F)/Denominator(r, MFR2F) eq r;
assert Numerator(r, EFR2I)/Denominator(r, EFR2I) eq r;
assert Numerator(r, MFR2I)/Denominator(r, MFR2I) eq r;

r := Random(FF2, 4);
assert Numerator(r, EFF2F)/Denominator(r, EFF2F) eq r;
assert Numerator(r, MFF2F)/Denominator(r, MFF2F) eq r;
assert Numerator(r, EFF2I)/Denominator(r, EFF2I) eq r;
assert Numerator(r, MFF2I)/Denominator(r, MFF2I) eq r;

r := Random(FR2, 3);
m, dn := Minimum(r, EFR2F);
assert m in CoefficientRing(EFR2F) meet dn*r*EFR2F;
r := Random(FR2, 3);
m, dn := Minimum(r, MFR2F);
assert m in CoefficientRing(MFR2F) meet dn*r*MFR2F;
r := Random(FR2, 3);
m, dn := Minimum(r, EFR2I);
assert m in CoefficientRing(EFR2I) meet dn*r*EFR2I;
r := Random(FR2, 3);
m, dn := Minimum(r, MFR2I);
assert m in CoefficientRing(MFR2I) meet dn*r*MFR2I;

r := Random(FF2, 3);
m, dn := Minimum(r, EFF2F);
assert m in CoefficientRing(EFF2F) meet dn*r*EFF2F;
r := Random(FF2, 3);
m, dn := Minimum(r, MFF2F);
assert m in CoefficientRing(MFF2F) meet dn*r*MFF2F;
r := Random(FF2, 3);
m, dn := Minimum(r, EFF2I);
assert m in CoefficientRing(EFF2I) meet dn*r*EFF2I;
r := Random(FF2, 3);
m, dn := Minimum(r, MFF2I);
assert m in CoefficientRing(MFF2I) meet dn*r*MFF2I;

r := Random(EFR2F, 3);
m, dn := Minimum(r, EFR2F);
assert m in CoefficientRing(EFR2F) meet dn*r*EFR2F;
r := Random(EFR2F, 3);
m, dn := Minimum(r, MFR2F);
assert m in CoefficientRing(MFR2F) meet dn*r*MFR2F;
r := Random(EFR2F, 3);
m, dn := Minimum(r, EFR2I);
assert m in CoefficientRing(EFR2I) meet dn*r*EFR2I;
r := Random(EFR2F, 3);
m, dn := Minimum(r, MFR2I);
assert m in CoefficientRing(MFR2I) meet dn*r*MFR2I;

r := Random(MFR2F, 3);
m, dn := Minimum(r, EFR2F);
assert m in CoefficientRing(EFR2F) meet dn*r*EFR2F;
r := Random(MFR2F, 3);
m, dn := Minimum(r, MFR2F);
assert m in CoefficientRing(MFR2F) meet dn*r*MFR2F;
r := Random(MFR2F, 3);
m, dn := Minimum(r, EFR2I);
assert m in CoefficientRing(EFR2I) meet dn*r*EFR2I;
r := Random(MFR2F, 3);
m, dn := Minimum(r, MFR2I);
assert m in CoefficientRing(MFR2I) meet dn*r*MFR2I;

r := Random(EFR2I, 2);
m, dn := Minimum(r, EFR2F);
assert m in CoefficientRing(EFR2F) meet dn*r*EFR2F;
r := Random(EFR2I, 2);
m, dn := Minimum(r, MFR2F);
assert m in CoefficientRing(MFR2F) meet dn*r*MFR2F;
r := Random(EFR2I, 2);
m, dn := Minimum(r, EFR2I);
assert m in CoefficientRing(EFR2I) meet dn*r*EFR2I;
r := Random(EFR2I, 2);
m, dn := Minimum(r, MFR2I);
assert m in CoefficientRing(MFR2I) meet dn*r*MFR2I;

r := Random(MFR2I, 2);
m, dn := Minimum(r, EFR2F);
assert m in CoefficientRing(EFR2F) meet dn*r*EFR2F;
r := Random(MFR2I, 2);
m, dn := Minimum(r, MFR2F);
assert m in CoefficientRing(MFR2F) meet dn*r*MFR2F;
r := Random(MFR2I, 2);
m, dn := Minimum(r, EFR2I);
assert m in CoefficientRing(EFR2I) meet dn*r*EFR2I;
r := Random(MFR2I, 2);
m, dn := Minimum(r, MFR2I);
assert m in CoefficientRing(MFR2I) meet dn*r*MFR2I;

r := Random(EFF2F, 3);
m, dn := Minimum(r, EFF2F);
assert m in CoefficientRing(EFF2F) meet dn*r*EFF2F;
r := Random(EFF2F, 3);
m, dn := Minimum(r, MFF2F);
assert m in CoefficientRing(MFF2F) meet dn*r*MFF2F;
r := Random(EFF2F, 3);
m, dn := Minimum(r, EFF2I);
assert m in CoefficientRing(EFF2I) meet dn*r*EFF2I;
r := Random(EFF2F, 3);
m, dn := Minimum(r, MFF2I);
assert m in CoefficientRing(MFF2I) meet dn*r*MFF2I;

r := Random(MFF2F, 3);
m, dn := Minimum(r, EFF2F);
assert m in CoefficientRing(EFF2F) meet dn*r*EFF2F;
r := Random(MFF2F, 3);
m, dn := Minimum(r, MFF2F);
assert m in CoefficientRing(MFF2F) meet dn*r*MFF2F;
r := Random(MFF2F, 3);
m, dn := Minimum(r, EFF2I);
assert m in CoefficientRing(EFF2I) meet dn*r*EFF2I;
r := Random(MFF2F, 3);
m, dn := Minimum(r, MFF2I);
assert m in CoefficientRing(MFF2I) meet dn*r*MFF2I;

r := Random(EFF2I, 3);
m, dn := Minimum(r, EFF2F);
assert m in CoefficientRing(EFF2F) meet dn*r*EFF2F;
r := Random(EFF2I, 3);
m, dn := Minimum(r, MFF2F);
assert m in CoefficientRing(MFF2F) meet dn*r*MFF2F;
r := Random(EFF2I, 3);
m, dn := Minimum(r, EFF2I);
assert m in CoefficientRing(EFF2I) meet dn*r*EFF2I;
r := Random(EFF2I, 3);
m, dn := Minimum(r, MFF2I);
assert m in CoefficientRing(MFF2I) meet dn*r*MFF2I;

r := Random(MFF2I, 3);
m, dn := Minimum(r, EFF2F);
assert m in CoefficientRing(EFF2F) meet dn*r*EFF2F;
r := Random(MFF2I, 3);
m, dn := Minimum(r, MFF2F);
assert m in CoefficientRing(MFF2F) meet dn*r*MFF2F;
r := Random(MFF2I, 3);
m, dn := Minimum(r, EFF2I);
assert m in CoefficientRing(EFF2I) meet dn*r*EFF2I;
r := Random(MFF2I, 3);
m, dn := Minimum(r, MFF2I);
assert m in CoefficientRing(MFF2I) meet dn*r*MFF2I;

check_mats_and_polys_etc := procedure(r)

    P := Parent(r);
    F := P;
    if not IsField(F) then
	F := FunctionField(F);
    end if;
    CF := CoefficientField(F);
    EI := EquationOrderInfinite(CF);
    MI := MaximalOrderInfinite(CF);
    EF := EquationOrderFinite(CF);
    MF := MaximalOrderFinite(CF);
    CCF := CoefficientField(CF);
    BF := CoefficientRing(EF);
    BI := CoefficientRing(EI);
    assert Evaluate(MinimalPolynomial(r), r) eq 0;
    assert Evaluate(MinimalPolynomial(r, EI), r) eq 0;
    assert Evaluate(MinimalPolynomial(r, MF), r) eq 0;
    assert Evaluate(MinimalPolynomial(r, EF), r) eq 0;
    assert Evaluate(MinimalPolynomial(r, MI), r) eq 0;
    assert Evaluate(MinimalPolynomial(r, CF), r) eq 0;
    assert Evaluate(MinimalPolynomial(r, BF), r) eq 0;
    assert Evaluate(MinimalPolynomial(r, CCF), r) eq 0;
    assert Evaluate(MinimalPolynomial(r, BI), r) eq 0;
    assert Evaluate(CharacteristicPolynomial(r), r) eq 0;
    assert Evaluate(CharacteristicPolynomial(r, EF), r) eq 0;
    assert Evaluate(CharacteristicPolynomial(r, MI), r) eq 0;
    assert Evaluate(CharacteristicPolynomial(r, EI), r) eq 0;
    assert Evaluate(CharacteristicPolynomial(r, MF), r) eq 0;
    assert Evaluate(CharacteristicPolynomial(r, CF), r) eq 0;
    assert Evaluate(CharacteristicPolynomial(r, BF), r) eq 0;
    assert Evaluate(CharacteristicPolynomial(r, CCF), r) eq 0;
    assert Evaluate(CharacteristicPolynomial(r, BI), r) eq 0;
    assert Trace(r) eq Trace(r, CoefficientRing(P));
    t := Trace(r);
    if t in EI then
	Trace(r, EI);
	Trace(r, MI);
	Trace(r, BI);
    end if;
    if t in EF then
	Trace(r, MF);
	Trace(r, EF);
	Trace(r, BF);
    end if;
    Trace(r, CF);
    Trace(r, CCF);
    assert Norm(r) eq Norm(r, CoefficientRing(P));
    Norm(r, CF);
    n := Norm(r);
    if n in EF then
	Norm(r, EF);
	Norm(r, MF);
	Norm(r, BF);
    end if;
    if n in EI then
	Norm(r, MI);
	Norm(r, EI);
	Norm(r, BI);
    end if;
    Norm(r, CCF);
    mr := RepresentationMatrix(r);
    s := Random(P, 2);
    ms := Matrix(1, Degree(P), Eltseq(s));
    assert P!Eltseq(ChangeRing(ms, CoefficientRing(P))*mr) eq s*r;
    mr := RepresentationMatrix(r, CoefficientRing(P));
    assert P!Eltseq(ChangeRing(ms, CoefficientRing(P))*mr) eq s*r;
    if n in EF then
	mr := RepresentationMatrix(r, EF);
	assert P!Eltseq(ChangeRing(ms, EF)*mr) eq s*r;
	mr := RepresentationMatrix(r, MF);
	assert P!Eltseq(ChangeRing(ms, MF)*mr) eq s*r;
	mr := RepresentationMatrix(r, BF);
	assert P![CF!q : q in [e[(i - 1)*Degree(CF) + 1 .. i*Degree(CF)] : 
	    i in [1 .. Degree(P)]]] eq s*r where 
	e is Eltseq(Matrix(BF, 1, 6, &cat[Eltseq(u) : u in Eltseq(s)])*mr);
    end if;
    if n in EI then
	mr := RepresentationMatrix(r, MI);
	assert P!Eltseq(ChangeRing(ms, MI)*mr) eq s*r;
	mr := RepresentationMatrix(r, EI);
	assert P!Eltseq(ChangeRing(ms, EI)*mr) eq s*r;
	mr := RepresentationMatrix(r, BI);
	assert P![CoefficientRing(P)!q : q in 
	    [e[(i - 1)*Degree(CF) + 1 .. i*Degree(CF)] : i in 
	    [1 .. Degree(P)]]] eq s*r where 
	e is Eltseq(Matrix(BI, 1, 6, &cat[Eltseq(CoefficientRing(P)!u) : 
	u in Eltseq(s)])*mr);
    end if;
    mr := RepresentationMatrix(r, CF);
    assert P!Eltseq(ChangeRing(ms, CF)*mr) eq s*r;
    mr := RepresentationMatrix(r, CCF);
    assert P![CoefficientRing(P)!q : q in 
	[e[(i - 1)*Degree(CF) + 1 .. i*Degree(CF)] : 
	i in [1 .. Degree(P)]]] eq s*r where 
    e is Eltseq(Matrix(CCF, 1, 6, &cat[Eltseq(CoefficientRing(P)!u) : 
    u in Eltseq(s)])*mr);
end procedure;

r := Random(FR2, 3);
check_mats_and_polys_etc(r);

r := Random(FF2, 3);
check_mats_and_polys_etc(r);

r := Random(EFR2F, 3);
check_mats_and_polys_etc(r);

r := Random(MFR2F, 3);
check_mats_and_polys_etc(r);

r := Random(EFR2I, 3);
check_mats_and_polys_etc(r);

r := Random(MFR2I, 3);
check_mats_and_polys_etc(r);

r := Random(EFF2F, 3);
check_mats_and_polys_etc(r);

r := Random(MFF2F, 3);
check_mats_and_polys_etc(r);

r := Random(EFF2I, 3);
check_mats_and_polys_etc(r);

r := Random(MFF2I, 3);
check_mats_and_polys_etc(r);

s, q := ProductRepresentation(c^20);
assert ProductRepresentation(s, q) eq c^20;
s, q := ProductRepresentation(d^17);
assert ProductRepresentation(s, q) eq d^17;

r := [FR2 | Random(EFR2F, 3) : i in [1 .. 4]];
repeat
    pr := ProductRepresentation(r, [Random(-4,4) : i in [1 .. 4]]);
    p, e := ProductRepresentation(pr);
until #p gt 0;
prc := &*[p[i]^e[i] : i in [1 .. #p]];
time assert pr eq prc;

D := Decomposition(EFR1F, CoefficientRing(EFR1F).1);
D := Decomposition(EFR2F, D[1]);
pl := Place(D[1]);
assert Valuation(pr, pl) eq Valuation(prc, pl);
_, rfmap := ResidueClassField(pl);
assert rfmap(pr) eq rfmap(prc);
assert Sprint(pr) ne Sprint(prc);

r := [FR2 | Random(MFR2F, 3) : i in [1 .. 4]];
repeat
    pr := ProductRepresentation(r, [Random(-4, 4) : i in [1 .. 4]]);
    p, e := ProductRepresentation(pr);
until #p gt 0;
prc := &*[p[i]^e[i] : i in [1 .. #p]];
time assert pr eq prc;

D := Decomposition(MFR1F, CoefficientRing(MFR1F).1);
D := Decomposition(MFR2F, D[1]);
pl := Place(D[1]);
assert Valuation(pr, pl) eq Valuation(prc, pl);
_, rfmap := ResidueClassField(pl);
assert rfmap(pr) eq rfmap(prc);
assert Sprint(pr) ne Sprint(prc);

r := [FR2 | Random(EFR2I, 3) : i in [1 .. 3]];
repeat 
    pr := ProductRepresentation(r, [Random(-1, 2) : i in [1 .. 3]]);
    p, e := ProductRepresentation(pr);
until #p gt 0;
prc := &*[p[i]^e[i] : i in [1 .. #p]];
time assert pr eq prc;

D := Decomposition(EFR1I, CoefficientRing(EFR1I)!(1/CoefficientRing(EFR1F).1));
D := Decomposition(EFR2I, D[1]);
pl := Place(D[1]);
assert Valuation(pr, pl) eq Valuation(prc, pl);
_, rfmap := ResidueClassField(pl);
assert rfmap(pr) eq rfmap(prc);
assert Sprint(pr) ne Sprint(prc);

r := [FR2 | Random(MFR2I, 3) : i in [1 .. 3]];
repeat
    pr := ProductRepresentation(r, [Random(-1, 2) : i in [1 .. 3]]);
    p, e := ProductRepresentation(pr);
until #p gt 0;
prc := &*[p[i]^e[i] : i in [1 .. #p]];
time assert pr eq prc;

D := Decomposition(MFR1I, CoefficientRing(MFR1I)!(1/CoefficientRing(EFR1F).1));
D := Decomposition(MFR2I, D[1]);
pl := Place(D[1]);
assert Valuation(pr, pl) eq Valuation(prc, pl);
_, rfmap := ResidueClassField(pl);
assert rfmap(pr) eq rfmap(prc);

r := [FF2 | Random(EFF2F, 3) : i in [1 .. 4]];
repeat
    pr := ProductRepresentation(r, [Random(-5, 5) : i in [1 .. 4]]);
    p, e := ProductRepresentation(pr);
until #p gt 0;
prc := &*[p[i]^e[i] : i in [1 .. #p]];
time assert pr eq prc;

D := Decomposition(EFF1F, CoefficientRing(EFF1F).1);
D := Decomposition(EFF2F, D[1]);
pl := Place(D[1]);
assert Valuation(pr, pl) eq Valuation(prc, pl);
_, rfmap := ResidueClassField(pl);
assert rfmap(pr) eq rfmap(prc);

r := [FF2 | Random(MFF2F, 3) : i in [1 .. 4]];
repeat
    pr := ProductRepresentation(r, [Random(-5, 5) : i in [1 .. 4]]);
    p, e := ProductRepresentation(pr);
until #p gt 0;
prc := &*[p[i]^e[i] : i in [1 .. #p]];
time assert pr eq prc;

D := Decomposition(MFF1F, CoefficientRing(MFF1F).1);
D := Decomposition(MFF2F, D[1]);
pl := Place(D[1]);
assert Valuation(pr, pl) eq Valuation(prc, pl);
_, rfmap := ResidueClassField(pl);
assert rfmap(pr) eq rfmap(prc);

r := [FF2 | Random(EFF2I, 3) : i in [1 .. 4]];
repeat
    pr := ProductRepresentation(r, [Random(-5, 5) : i in [1 .. 4]]);
    p, e := ProductRepresentation(pr);
until #p gt 0;
prc := &*[p[i]^e[i] : i in [1 .. #p]];
time assert pr eq prc;

D := Decomposition(EFF1I, CoefficientRing(EFF1I)!(1/CoefficientRing(EFF1F).1));
D := Decomposition(EFF2I, D[1]);
pl := Place(D[1]);
assert Valuation(pr, pl) eq Valuation(prc, pl);
_, rfmap := ResidueClassField(pl);
assert rfmap(pr) eq rfmap(prc);

r := [FF2 | Random(MFF2I, 3) : i in [1 .. 4]];
repeat
    pr := ProductRepresentation(r, [Random(-5, 5) : i in [1 .. 4]]);
    p, e := ProductRepresentation(pr);
until #p gt 0;
prc := &*[p[i]^e[i] : i in [1 .. #p]];
time assert pr eq prc;

D := Decomposition(MFF1I, CoefficientRing(MFF1I)!(1/CoefficientRing(MFF1F).1));
D := Decomposition(MFF2I, D[1]);
pl := Place(D[1]);
assert Valuation(pr, pl) eq Valuation(prc, pl);
_, rfmap := ResidueClassField(pl);
assert rfmap(pr) eq rfmap(prc);


RationalFunction(Random(FR2, 2));
RationalFunction(Random(FF2, 2));

RationalFunction(Random(FR2, 2), PR);
RationalFunction(Random(FF2, 2), PF);
RationalFunction(Random(FF2, 2), EFF1F);
RationalFunction(FF2!Random(EFF2I, 2), EFF1I);
RationalFunction(Random(FF2, 2), MFF1F);
RationalFunction(FF2!Random(MFF2I, 2), MFF1I);
RationalFunction(Random(FF2, 2), FieldOfFractions(PF));
RationalFunction(FF2!Random(EFF2I, 2), CoefficientRing(EFF1I));
RationalFunction(Random(FF2, 2), FF1);


Differentiation(c*PR.1, c^17);
Differentiation(d*PF.1, d^7);

Differentiation((c - 1)*PR.1, 3, c^17);
Differentiation(d*PF.1, 2, d^5);

Differentiation(c*PR.1, c^17*PR.1^5);
Differentiation(d*PF.1, d^5*PF.1^3);

Differentiation(c*PR.1 - 1, 3, c^6*PR.1^4);
Differentiation(FF2!PF.1, 2, d^4*PF.1);

