File size: 5,036 Bytes
6a86ad5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
"""Tests for computing Galois groups. """

from sympy.abc import x
from sympy.combinatorics.galois import (
    S1TransitiveSubgroups, S2TransitiveSubgroups, S3TransitiveSubgroups,
    S4TransitiveSubgroups, S5TransitiveSubgroups, S6TransitiveSubgroups,
)
from sympy.polys.domains.rationalfield import QQ
from sympy.polys.numberfields.galoisgroups import (
    tschirnhausen_transformation,
    galois_group,
    _galois_group_degree_4_root_approx,
    _galois_group_degree_5_hybrid,
)
from sympy.polys.numberfields.subfield import field_isomorphism
from sympy.polys.polytools import Poly
from sympy.testing.pytest import raises


def test_tschirnhausen_transformation():
    for T in [
        Poly(x**2 - 2),
        Poly(x**2 + x + 1),
        Poly(x**4 + 1),
        Poly(x**4 - x**3 + x**2 - x + 1),
    ]:
        _, U = tschirnhausen_transformation(T)
        assert U.degree() == T.degree()
        assert U.is_monic
        assert U.is_irreducible
        K = QQ.alg_field_from_poly(T)
        L = QQ.alg_field_from_poly(U)
        assert field_isomorphism(K.ext, L.ext) is not None


# Test polys are from:
# Cohen, H. *A Course in Computational Algebraic Number Theory*.
test_polys_by_deg = {
    # Degree 1
    1: [
        (x, S1TransitiveSubgroups.S1, True)
    ],
    # Degree 2
    2: [
        (x**2 + x + 1, S2TransitiveSubgroups.S2, False)
    ],
    # Degree 3
    3: [
        (x**3 + x**2 - 2*x - 1, S3TransitiveSubgroups.A3, True),
        (x**3 + 2, S3TransitiveSubgroups.S3, False),
    ],
    # Degree 4
    4: [
        (x**4 + x**3 + x**2 + x + 1, S4TransitiveSubgroups.C4, False),
        (x**4 + 1, S4TransitiveSubgroups.V, True),
        (x**4 - 2, S4TransitiveSubgroups.D4, False),
        (x**4 + 8*x + 12, S4TransitiveSubgroups.A4, True),
        (x**4 + x + 1, S4TransitiveSubgroups.S4, False),
    ],
    # Degree 5
    5: [
        (x**5 + x**4 - 4*x**3 - 3*x**2 + 3*x + 1, S5TransitiveSubgroups.C5, True),
        (x**5 - 5*x + 12, S5TransitiveSubgroups.D5, True),
        (x**5 + 2, S5TransitiveSubgroups.M20, False),
        (x**5 + 20*x + 16, S5TransitiveSubgroups.A5, True),
        (x**5 - x + 1, S5TransitiveSubgroups.S5, False),
    ],
    # Degree 6
    6: [
        (x**6 + x**5 + x**4 + x**3 + x**2 + x + 1, S6TransitiveSubgroups.C6, False),
        (x**6 + 108, S6TransitiveSubgroups.S3, False),
        (x**6 + 2, S6TransitiveSubgroups.D6, False),
        (x**6 - 3*x**2 - 1, S6TransitiveSubgroups.A4, True),
        (x**6 + 3*x**3 + 3, S6TransitiveSubgroups.G18, False),
        (x**6 - 3*x**2 + 1, S6TransitiveSubgroups.A4xC2, False),
        (x**6 - 4*x**2 - 1, S6TransitiveSubgroups.S4p, True),
        (x**6 - 3*x**5 + 6*x**4 - 7*x**3 + 2*x**2 + x - 4, S6TransitiveSubgroups.S4m, False),
        (x**6 + 2*x**3 - 2, S6TransitiveSubgroups.G36m, False),
        (x**6 + 2*x**2 + 2, S6TransitiveSubgroups.S4xC2, False),
        (x**6 + 10*x**5 + 55*x**4 + 140*x**3 + 175*x**2 + 170*x + 25, S6TransitiveSubgroups.PSL2F5, True),
        (x**6 + 10*x**5 + 55*x**4 + 140*x**3 + 175*x**2 - 3019*x + 25, S6TransitiveSubgroups.PGL2F5, False),
        (x**6 + 6*x**4 + 2*x**3 + 9*x**2 + 6*x - 4, S6TransitiveSubgroups.G36p, True),
        (x**6 + 2*x**4 + 2*x**3 + x**2 + 2*x + 2, S6TransitiveSubgroups.G72, False),
        (x**6 + 24*x - 20, S6TransitiveSubgroups.A6, True),
        (x**6 + x + 1, S6TransitiveSubgroups.S6, False),
    ],
}


def test_galois_group():
    """
    Try all the test polys.
    """
    for deg in range(1, 7):
        polys = test_polys_by_deg[deg]
        for T, G, alt in polys:
            assert galois_group(T, by_name=True) == (G, alt)


def test_galois_group_degree_out_of_bounds():
    raises(ValueError, lambda: galois_group(Poly(0, x)))
    raises(ValueError, lambda: galois_group(Poly(1, x)))
    raises(ValueError, lambda: galois_group(Poly(x ** 7 + 1)))


def test_galois_group_not_by_name():
    """
    Check at least one polynomial of each supported degree, to see that
    conversion from name to group works.
    """
    for deg in range(1, 7):
        T, G_name, _ = test_polys_by_deg[deg][0]
        G, _ = galois_group(T)
        assert G == G_name.get_perm_group()


def test_galois_group_not_monic_over_ZZ():
    """
    Check that we can work with polys that are not monic over ZZ.
    """
    for deg in range(1, 7):
        T, G, alt = test_polys_by_deg[deg][0]
        assert galois_group(T/2, by_name=True) == (G, alt)


def test__galois_group_degree_4_root_approx():
    for T, G, alt in test_polys_by_deg[4]:
        assert _galois_group_degree_4_root_approx(Poly(T)) == (G, alt)


def test__galois_group_degree_5_hybrid():
    for T, G, alt in test_polys_by_deg[5]:
        assert _galois_group_degree_5_hybrid(Poly(T)) == (G, alt)


def test_AlgebraicField_galois_group():
    k = QQ.alg_field_from_poly(Poly(x**4 + 1))
    G, _ = k.galois_group(by_name=True)
    assert G == S4TransitiveSubgroups.V

    k = QQ.alg_field_from_poly(Poly(x**4 - 2))
    G, _ = k.galois_group(by_name=True)
    assert G == S4TransitiveSubgroups.D4