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

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

# -*- coding: utf-8 -*- 

r""" 

Valuations on polynomial rings based on `\phi`-adic expansions 

 

This file implements a base class for discrete valuations on polynomial rings, 

defined by a `\phi`-adic expansion. 

 

AUTHORS: 

 

- Julian Rüth (2013-04-15): initial version 

 

EXAMPLES: 

 

The :mod:`Gauss valuation <sage.rings.valuation.gauss_valuation>` is a simple example of a valuation that relies on 

`\phi`-adic expansions:: 

 

sage: R.<x> = QQ[] 

sage: v = GaussValuation(R, QQ.valuation(2)) 

 

In this case, `\phi = x`, so the expansion simply lists the coefficients of the 

polynomial:: 

 

sage: f = x^2 + 2*x + 2 

sage: list(v.coefficients(f)) 

[2, 2, 1] 

 

Often only the first few coefficients are necessary in computations, so for 

performance reasons, coefficients are computed lazily:: 

 

sage: v.coefficients(f) 

<generator object coefficients at 0x...> 

 

Another example of a :class:`DevelopingValuation` is an :mod:`augmented 

valuation <sage.rings.valuation.augmented_valuation>`:: 

 

sage: w = v.augmentation(x^2 + x + 1, 3) 

 

Here, the expansion lists the remainders of repeated division by `x^2 + x + 1`:: 

 

sage: list(w.coefficients(f)) 

[x + 1, 1] 

 

""" 

#***************************************************************************** 

# Copyright (C) 2013-2017 Julian Rüth <julian.rueth@fsfe.org> 

# 

# Distributed under the terms of the GNU General Public License (GPL) 

# as published by the Free Software Foundation; either version 2 of 

# the License, or (at your option) any later version. 

# http://www.gnu.org/licenses/ 

#***************************************************************************** 

from __future__ import absolute_import 

 

from .valuation import DiscretePseudoValuation 

from sage.misc.abstract_method import abstract_method 

 

from sage.misc.cachefunc import cached_method 

 

 

class DevelopingValuation(DiscretePseudoValuation): 

r""" 

Abstract base class for a discrete valuation of polynomials defined over 

the polynomial ring ``domain`` by the `\phi`-adic development. 

 

EXAMPLES:: 

 

sage: R.<x> = QQ[] 

sage: v = GaussValuation(R, QQ.valuation(7)) 

 

TESTS:: 

 

sage: TestSuite(v).run() # long time 

 

""" 

def __init__(self, parent, phi): 

r""" 

TESTS:: 

 

sage: R.<x> = QQ[] 

sage: v = GaussValuation(R, QQ.valuation(7)) 

sage: from sage.rings.valuation.developing_valuation import DevelopingValuation 

sage: isinstance(v, DevelopingValuation) 

True 

 

""" 

DiscretePseudoValuation.__init__(self, parent) 

 

domain = parent.domain() 

from sage.rings.polynomial.polynomial_ring import is_PolynomialRing 

if not is_PolynomialRing(domain) or not domain.ngens() == 1: 

raise TypeError("domain must be a univariate polynomial ring but %r is not"%(domain,)) 

 

phi = domain.coerce(phi) 

if phi.is_constant() or not phi.is_monic(): 

raise ValueError("phi must be a monic non-constant polynomial but %r is not"%(phi,)) 

 

self._phi = phi 

 

def phi(self): 

r""" 

Return the polynomial `\phi`, the key polynomial of this valuation. 

 

EXAMPLES:: 

 

sage: R = Zp(2,5) 

sage: S.<x> = R[] 

sage: v = GaussValuation(S) 

sage: v.phi() 

(1 + O(2^5))*x 

 

""" 

return self._phi 

 

def effective_degree(self, f, valuations=None): 

r""" 

Return the effective degree of ``f`` with respect to this valuation. 

 

The effective degree of `f` is the largest `i` such that the valuation 

of `f` and the valuation of `f_i\phi^i` in the development `f=\sum_j 

f_j\phi^j` coincide (see [Mac1936II]_ p.497.) 

 

INPUT: 

 

- ``f`` -- a non-zero polynomial in the domain of this valuation 

 

EXAMPLES:: 

 

sage: R = Zp(2,5) 

sage: S.<x> = R[] 

sage: v = GaussValuation(S) 

sage: v.effective_degree(x) 

1 

sage: v.effective_degree(2*x + 1) 

0 

 

""" 

f = self.domain().coerce(f) 

 

if f.is_zero(): 

raise ValueError("the effective degree is only defined for non-zero polynomials") 

 

if valuations is None: 

valuations = list(self.valuations(f)) 

v = min(valuations) 

return [i for i,w in enumerate(valuations) if w == v][-1] 

 

@cached_method 

def _pow(self, f, e, error, effective_degree): 

r""" 

Return `f^e`. 

 

This method does not compute the exact value of `f^e` but only an 

element that differs from the correct result by an error with valuation 

at least ``error``. The output is assumed to have at most 

``effective_degree``. If the effective degree is higher than 

``effective_degree``, then the result may not be correct. 

 

EXAMPLES:: 

 

sage: R = Zp(2,5) 

sage: S.<x> = R[] 

sage: v = GaussValuation(S) 

sage: v._pow(2*x + 1, 10, effective_degree=0, error=5) 

(1 + O(2^5)) 

 

""" 

if e == 0: 

return self.domain().one() 

if e == 1: 

return self.simplify(f, error=error) 

if e % 2 == 0: 

return self._pow(self.simplify(f*f, error=error*2/e, effective_degree=effective_degree*2/e), 

e//2, error=error, effective_degree=effective_degree) 

else: 

return self.simplify(f*self._pow(f, e-1, error=error*(e-1)/e, effective_degree=effective_degree*(e-1)/e), 

error=error, effective_degree=effective_degree) 

 

def coefficients(self, f): 

r""" 

Return the `\phi`-adic expansion of ``f``. 

 

INPUT: 

 

- ``f`` -- a monic polynomial in the domain of this valuation 

 

OUTPUT: 

 

An iterator `f_0, f_1, \dots, f_n` of polynomials in the domain of this 

valuation such that `f=\sum_i f_i\phi^i` 

 

EXAMPLES:: 

 

sage: R = Qp(2,5) 

sage: S.<x> = R[] 

sage: v = GaussValuation(S) 

sage: f = x^2 + 2*x + 3 

sage: list(v.coefficients(f)) # note that these constants are in the polynomial ring 

[(1 + 2 + O(2^5)), (2 + O(2^6)), (1 + O(2^5))] 

sage: v = v.augmentation( x^2 + x + 1, 1) 

sage: list(v.coefficients(f)) 

[(1 + O(2^5))*x + (2 + O(2^5)), (1 + O(2^5))] 

 

""" 

domain = self.domain() 

f = domain.coerce(f) 

 

if f.degree() < self.phi().degree(): 

yield f 

elif self.phi().degree() == 1: 

if self.phi() != domain.gen() or not domain.is_exact(): 

f = f(domain.gen() - self.phi()[0]) 

for c in f.coefficients(sparse=False): 

yield domain(c) 

else: 

while f.degree() >= 0: 

f,r = self._quo_rem(f) 

yield r 

 

def _quo_rem(self, f): 

r""" 

Return the quotient and remainder of ``f`` divided by the key 

polynomial :meth:`phi`. 

 

EXAMPLES:: 

 

sage: S.<x> = QQ[] 

sage: v = GaussValuation(S, QQ.valuation(2)) 

sage: v._quo_rem(x^2 + 1) 

(x, 1) 

 

""" 

return f.quo_rem(self.phi()) 

 

def newton_polygon(self, f, valuations=None): 

r""" 

Return the newton polygon of the `\phi`-adic development of ``f``. 

 

INPUT: 

 

- ``f`` -- a polynomial in the domain of this valuation 

 

EXAMPLES:: 

 

sage: R = Qp(2,5) 

sage: S.<x> = R[] 

sage: v = GaussValuation(S) 

sage: f = x^2 + 2*x + 3 

sage: v.newton_polygon(f) 

Finite Newton polygon with 2 vertices: (0, 0), (2, 0) 

 

sage: v = v.augmentation( x^2 + x + 1, 1) 

sage: v.newton_polygon(f) 

Finite Newton polygon with 2 vertices: (0, 0), (1, 1) 

sage: v.newton_polygon( f * v.phi()^3 ) 

Finite Newton polygon with 2 vertices: (3, 3), (4, 4) 

 

""" 

f = self.domain().coerce(f) 

 

from sage.geometry.newton_polygon import NewtonPolygon 

if valuations is None: 

valuations = self.valuations(f) 

return NewtonPolygon(list(enumerate(valuations))) 

 

def _call_(self, f): 

r""" 

Evaluate this valuation at ``f``. 

 

INPUT: 

 

- ``f`` -- a polynomial in the domain of this valuation 

 

EXAMPLES:: 

 

sage: R = Qp(2,5) 

sage: S.<x> = R[] 

sage: v = GaussValuation(S) 

sage: f = x^2 + 2*x + 3 

sage: v(f) 

0 

 

sage: v = v.augmentation( x^2 + x + 1, 1) 

sage: v(f) 

0 

sage: v(f * v.phi()^3 ) 

3 

sage: v(S.zero()) 

+Infinity 

 

""" 

f = self.domain().coerce(f) 

 

from sage.rings.all import infinity 

if f.is_zero(): 

return infinity 

 

ret = infinity 

for v in self.valuations(f, call_error=True): 

if ret is infinity or (v is not infinity and v < ret): 

# "ret is infinity" is redundant but much faster than < when ret is infinite 

ret = v 

return ret 

 

@abstract_method 

def valuations(self, f): 

r""" 

Return the valuations of the `f_i\phi^i` in the expansion `f=\sum f_i\phi^i`. 

 

INPUT: 

 

- ``f`` -- a polynomial in the domain of this valuation 

 

OUTPUT: 

 

A list, each entry a rational numbers or infinity, the valuations of 

`f_0, f_1\phi, \dots` 

 

EXAMPLES:: 

 

sage: R = Qp(2,5) 

sage: S.<x> = R[] 

sage: v = GaussValuation(S, R.valuation()) 

sage: f = x^2 + 2*x + 16 

sage: list(v.valuations(f)) 

[4, 1, 0] 

 

""" 

 

def _test_effective_degree(self, **options): 

r""" 

Test the correctness of :meth:`effective_degree`. 

 

EXAMPLES:: 

 

sage: R = Zp(2,5) 

sage: S.<x> = R[] 

sage: v = GaussValuation(S) 

sage: v._test_effective_degree() 

 

""" 

tester = self._tester(**options) 

S = tester.some_elements(self.domain().base_ring().some_elements()) 

for x in S: 

if x == 0: 

continue 

tester.assertEqual(self.effective_degree(x), 0)