Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

145

146

147

148

149

150

151

"""Heuristic polynomial GCD algorithm (HEUGCD). """ 

 

from __future__ import print_function, division 

from sympy.core.compatibility import range 

from .polyerrors import HeuristicGCDFailed 

 

HEU_GCD_MAX = 6 

 

def heugcd(f, g): 

""" 

Heuristic polynomial GCD in ``Z[X]``. 

 

Given univariate polynomials ``f`` and ``g`` in ``Z[X]``, returns 

their GCD and cofactors, i.e. polynomials ``h``, ``cff`` and ``cfg`` 

such that:: 

 

h = gcd(f, g), cff = quo(f, h) and cfg = quo(g, h) 

 

The algorithm is purely heuristic which means it may fail to compute 

the GCD. This will be signaled by raising an exception. In this case 

you will need to switch to another GCD method. 

 

The algorithm computes the polynomial GCD by evaluating polynomials 

``f`` and ``g`` at certain points and computing (fast) integer GCD 

of those evaluations. The polynomial GCD is recovered from the integer 

image by interpolation. The evaluation proces reduces f and g variable 

by variable into a large integer. The final step is to verify if the 

interpolated polynomial is the correct GCD. This gives cofactors of 

the input polynomials as a side effect. 

 

Examples 

======== 

 

>>> from sympy.polys.heuristicgcd import heugcd 

>>> from sympy.polys import ring, ZZ 

 

>>> R, x,y, = ring("x,y", ZZ) 

 

>>> f = x**2 + 2*x*y + y**2 

>>> g = x**2 + x*y 

 

>>> h, cff, cfg = heugcd(f, g) 

>>> h, cff, cfg 

(x + y, x + y, x) 

 

>>> cff*h == f 

True 

>>> cfg*h == g 

True 

 

References 

========== 

 

1. [Liao95]_ 

 

""" 

assert f.ring == g.ring and f.ring.domain.is_ZZ 

 

ring = f.ring 

x0 = ring.gens[0] 

domain = ring.domain 

 

gcd, f, g = f.extract_ground(g) 

 

f_norm = f.max_norm() 

g_norm = g.max_norm() 

 

B = domain(2*min(f_norm, g_norm) + 29) 

 

x = max(min(B, 99*domain.sqrt(B)), 

2*min(f_norm // abs(f.LC), 

g_norm // abs(g.LC)) + 2) 

 

for i in range(0, HEU_GCD_MAX): 

ff = f.evaluate(x0, x) 

gg = g.evaluate(x0, x) 

 

if ff and gg: 

if ring.ngens == 1: 

h, cff, cfg = domain.cofactors(ff, gg) 

else: 

h, cff, cfg = heugcd(ff, gg) 

 

h = _gcd_interpolate(h, x, ring) 

h = h.primitive()[1] 

 

cff_, r = f.div(h) 

 

if not r: 

cfg_, r = g.div(h) 

 

if not r: 

h = h.mul_ground(gcd) 

return h, cff_, cfg_ 

 

cff = _gcd_interpolate(cff, x, ring) 

 

h, r = f.div(cff) 

 

if not r: 

cfg_, r = g.div(h) 

 

if not r: 

h = h.mul_ground(gcd) 

return h, cff, cfg_ 

 

cfg = _gcd_interpolate(cfg, x, ring) 

 

h, r = g.div(cfg) 

 

if not r: 

cff_, r = f.div(h) 

 

if not r: 

h = h.mul_ground(gcd) 

return h, cff_, cfg 

 

x = 73794*x * domain.sqrt(domain.sqrt(x)) // 27011 

 

raise HeuristicGCDFailed('no luck') 

 

def _gcd_interpolate(h, x, ring): 

"""Interpolate polynomial GCD from integer GCD. """ 

f, i = ring.zero, 0 

 

# TODO: don't expose poly repr implementation details 

if ring.ngens == 1: 

while h: 

g = h % x 

if g > x // 2: g -= x 

h = (h - g) // x 

 

# f += X**i*g 

if g: 

f[(i,)] = g 

i += 1 

else: 

while h: 

g = h.trunc_ground(x) 

h = (h - g).quo_ground(x) 

 

# f += X**i*g 

if g: 

for monom, coeff in g.iterterms(): 

f[(i,) + monom] = coeff 

i += 1 

 

if f.LC < 0: 

return -f 

else: 

return f