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

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

412

413

414

415

416

417

418

419

420

421

422

423

424

425

426

r""" 

Interface to LattE integrale programs 

""" 

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

# Copyright (C) 2017 Vincent Delecroix <vincent.delecroix@gmail.com> 

# 

# This program is free software: you can redistribute it and/or modify 

# it under the terms of the GNU General Public License 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/ 

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

 

import six 

 

def count(arg, ehrhart_polynomial=False, multivariate_generating_function=False, raw_output=False, verbose=False, **kwds): 

r""" 

Call to the program count from LattE integrale 

 

INPUT: 

 

- ``arg`` -- a cdd or LattE description string 

 

- ``ehrhart_polynomial``, ``multivariate_generating_function`` -- to 

compute Ehrhart polynomial or multivariate generating function instead of 

just counting points 

 

- ``raw_output`` -- if ``True`` then return directly the output string from LattE 

 

- For all other options of the count program, consult the LattE manual 

 

OUTPUT: 

 

Either a string (if ``raw_output`` if set to ``True``) or an integer (when 

counting points), or a polynomial (if ``ehrhart_polynomial`` is set to 

``True``) or a multivariate THING (if ``multivariate_generating_function`` 

is set to ``True``) 

 

EXAMPLES:: 

 

sage: from sage.interfaces.latte import count 

sage: P = 2 * polytopes.cube() 

 

Counting integer points from either the H or V representation:: 

 

sage: count(P.cdd_Hrepresentation(), cdd=True) # optional - latte_int 

125 

sage: count(P.cdd_Vrepresentation(), cdd=True) # optional - latte_int 

125 

 

Ehrhart polynomial:: 

 

sage: count(P.cdd_Hrepresentation(), cdd=True, ehrhart_polynomial=True) # optional - latte_int 

64*t^3 + 48*t^2 + 12*t + 1 

 

Multivariate generating function currently only work with ``raw_output=True``:: 

 

sage: opts = {'cdd': True, 

....: 'multivariate_generating_function': True, 

....: 'raw_output': True} 

sage: cddin = P.cdd_Hrepresentation() 

sage: print(count(cddin, **opts)) # optional - latte_int 

x[0]^2*x[1]^(-2)*x[2]^(-2)/((1-x[1])*(1-x[2])*(1-x[0]^(-1))) 

+ x[0]^(-2)*x[1]^(-2)*x[2]^(-2)/((1-x[1])*(1-x[2])*(1-x[0])) 

+ x[0]^2*x[1]^(-2)*x[2]^2/((1-x[1])*(1-x[0]^(-1))*(1-x[2]^(-1))) 

+ x[0]^(-2)*x[1]^(-2)*x[2]^2/((1-x[1])*(1-x[0])*(1-x[2]^(-1))) 

+ x[0]^2*x[1]^2*x[2]^(-2)/((1-x[2])*(1-x[0]^(-1))*(1-x[1]^(-1))) 

+ x[0]^(-2)*x[1]^2*x[2]^(-2)/((1-x[2])*(1-x[0])*(1-x[1]^(-1))) 

+ x[0]^2*x[1]^2*x[2]^2/((1-x[0]^(-1))*(1-x[1]^(-1))*(1-x[2]^(-1))) 

+ x[0]^(-2)*x[1]^2*x[2]^2/((1-x[0])*(1-x[1]^(-1))*(1-x[2]^(-1))) 

 

TESTS: 

 

Testing raw output:: 

 

sage: from sage.interfaces.latte import count 

sage: P = polytopes.cuboctahedron() 

sage: cddin = P.cdd_Vrepresentation() 

sage: count(cddin, cdd=True, raw_output=True) # optional - latte_int 

'19' 

sage: count(cddin, cdd=True, raw_output=True, ehrhart_polynomial=True) # optional - latte_int 

' + 1 * t^0 + 10/3 * t^1 + 8 * t^2 + 20/3 * t^3' 

sage: count(cddin, cdd=True, raw_output=True, multivariate_generating_function=True) # optional - latte_int 

'x[0]^(-1)*x[1]^(-1)/((1-x[0]*x[2])*(1-x[0]^(-1)*x[1])*...x[0]^(-1)*x[2]^(-1)))\n' 

 

Testing the ``verbose`` option:: 

 

sage: n = count(cddin, cdd=True, verbose=True, raw_output=True) # optional - latte_int 

This is LattE integrale ... 

... 

Invocation: count '--redundancy-check=none' --cdd /dev/stdin 

... 

Total Unimodular Cones: ... 

Maximum number of simplicial cones in memory at once: ... 

<BLANKLINE> 

**** The number of lattice points is: **** 

Total time: ... sec 

 

Trivial input for which LattE's preprocessor does all the work:: 

 

sage: P = Polyhedron(vertices=[[0,0,0]]) 

sage: cddin = P.cdd_Hrepresentation() 

sage: count(cddin, cdd=True, raw_output=False) # optional - latte_int 

1 

 

""" 

from subprocess import Popen, PIPE 

from sage.misc.misc import SAGE_TMP 

from sage.rings.integer import Integer 

 

args = ['count'] 

if ehrhart_polynomial and multivariate_generating_function: 

raise ValueError 

if ehrhart_polynomial: 

args.append('--ehrhart-polynomial') 

elif multivariate_generating_function: 

args.append('--multivariate-generating-function') 

 

if 'redundancy_check' not in kwds: 

args.append('--redundancy-check=none') 

 

for key,value in kwds.items(): 

if value is None or value is False: 

continue 

 

key = key.replace('_','-') 

if value is True: 

args.append('--{}'.format(key)) 

else: 

args.append('--{}={}'.format(key, value)) 

 

if multivariate_generating_function: 

from sage.misc.temporary_file import tmp_filename 

filename = tmp_filename() 

with open(filename, 'w') as f: 

f.write(arg) 

args += [filename] 

else: 

args += ['/dev/stdin'] 

 

try: 

# The cwd argument is needed because latte 

# always produces diagnostic output files. 

latte_proc = Popen(args, 

stdin=PIPE, stdout=PIPE, 

stderr=(None if verbose else PIPE), 

cwd=str(SAGE_TMP)) 

except OSError: 

from sage.misc.package import PackageNotFoundError 

raise PackageNotFoundError('latte_int') 

 

ans, err = latte_proc.communicate(arg) 

ret_code = latte_proc.poll() 

if ret_code: 

if err is None: 

err = ", see error message above" 

else: 

err = ":\n" + err 

raise RuntimeError("LattE integrale program failed (exit code {})".format(ret_code) + err.strip()) 

 

 

if ehrhart_polynomial: 

ans = ans.splitlines()[-2] 

if raw_output: 

return ans 

else: 

from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing 

from sage.rings.rational_field import QQ 

R = PolynomialRing(QQ, 't') 

return R(ans) 

elif multivariate_generating_function: 

with open(filename + '.rat') as f: 

ans = f.read() 

if raw_output: 

return ans 

else: 

raise NotImplementedError("there is no Sage object to handle multivariate series from LattE, use raw_output=True") 

else: 

if ans: # Sometimes (when LattE's preproc does the work), no output appears on stdout. 

ans = ans.splitlines()[-1] 

if not ans: 

# opening a file is slow (30e-6s), so we read the file 

# numOfLatticePoints only in case of a IndexError above 

with open(SAGE_TMP+'/numOfLatticePoints', 'r') as f: 

ans = f.read() 

 

if raw_output: 

return ans 

else: 

from sage.rings.integer import Integer 

return Integer(ans) 

 

def integrate(arg, polynomial=None, algorithm='triangulate', raw_output=False, verbose=False, **kwds): 

r""" 

Call to the function integrate from LattE integrale. 

 

INPUT: 

 

- ``arg`` -- a cdd or LattE description string. 

 

- ``polynomial`` -- multivariate polynomial or valid LattE polynomial description string. 

If given, the valuation parameter of LattE is set to integrate, and is set to volume otherwise. 

 

- ``algorithm`` -- (default: 'triangulate') the integration method. Use 'triangulate' for 

polytope triangulation or 'cone-decompose' for tangent cone decomposition method. 

 

- ``raw_output`` -- if ``True`` then return directly the output string from LattE. 

 

- ``verbose`` -- if ``True`` then return directly verbose output from LattE. 

 

- For all other options of the integrate program, consult the LattE manual. 

 

OUTPUT: 

 

Either a string (if ``raw_output`` if set to ``True``) or a rational. 

 

EXAMPLES:: 

 

sage: from sage.interfaces.latte import integrate 

sage: P = 2 * polytopes.cube() 

sage: x, y, z = polygen(QQ, 'x, y, z') 

 

Integrating over a polynomial over a polytope in either the H or V representation:: 

 

sage: integrate(P.cdd_Hrepresentation(), x^2*y^2*z^2, cdd=True) # optional - latte_int 

4096/27 

sage: integrate(P.cdd_Vrepresentation(), x^2*y^2*z^2, cdd=True) # optional - latte_int 

4096/27 

 

Computing the volume of a polytope in either the H or V representation:: 

 

sage: integrate(P.cdd_Hrepresentation(), cdd=True) # optional - latte_int 

64 

sage: integrate(P.cdd_Vrepresentation(), cdd=True) # optional - latte_int 

64 

 

Polynomials given as a string in LattE description are also accepted:: 

 

sage: integrate(P.cdd_Hrepresentation(), '[[1,[2,2,2]]]', cdd=True) # optional - latte_int 

4096/27 

 

TESTS:: 

 

Testing raw output:: 

 

sage: from sage.interfaces.latte import integrate 

sage: P = polytopes.cuboctahedron() 

sage: cddin = P.cdd_Vrepresentation() 

sage: x, y, z = polygen(QQ, 'x, y, z') 

sage: f = 3*x^2*y^4*z^6 + 7*y^3*z^5 

sage: integrate(cddin, f, cdd=True, raw_output=True) # optional - latte_int 

'629/47775' 

 

Testing the ``verbose`` option to integrate over a polytope:: 

 

sage: ans = integrate(cddin, f, cdd=True, verbose=True, raw_output=True) # optional - latte_int 

This is LattE integrale ... 

... 

Invocation: integrate --valuation=integrate --triangulate --redundancy-check=none --cdd --monomials=... /dev/stdin 

... 

 

Testing triangulate algorithm:: 

 

sage: from sage.interfaces.latte import integrate 

sage: P = polytopes.cuboctahedron() 

sage: cddin = P.cdd_Vrepresentation() 

sage: integrate(cddin, algorithm='triangulate', cdd=True) # optional - latte_int 

20/3 

 

Testing convex decomposition algorithm:: 

 

sage: from sage.interfaces.latte import integrate 

sage: P = polytopes.cuboctahedron() 

sage: cddin = P.cdd_Vrepresentation() 

sage: integrate(cddin, algorithm='cone-decompose', cdd=True) # optional - latte_int 

20/3 

 

Testing raw output:: 

 

sage: from sage.interfaces.latte import integrate 

sage: P = polytopes.cuboctahedron() 

sage: cddin = P.cdd_Vrepresentation() 

sage: integrate(cddin, cdd=True, raw_output=True) # optional - latte_int 

'20/3' 

 

Testing polynomial given as a string in LattE description:: 

 

sage: from sage.interfaces.latte import integrate 

sage: P = polytopes.cuboctahedron() 

sage: integrate(P.cdd_Hrepresentation(), '[[3,[2,4,6]],[7,[0, 3, 5]]]', cdd=True) # optional - latte_int 

629/47775 

 

Testing the ``verbose`` option to compute the volume of a polytope:: 

 

sage: from sage.interfaces.latte import integrate 

sage: P = polytopes.cuboctahedron() 

sage: cddin = P.cdd_Vrepresentation() 

sage: ans = integrate(cddin, cdd=True, raw_output=True, verbose=True) # optional - latte_int 

This is LattE integrale ... 

... 

Invocation: integrate --valuation=volume --triangulate --redundancy-check=none --cdd /dev/stdin 

... 

""" 

from subprocess import Popen, PIPE 

from sage.misc.misc import SAGE_TMP 

from sage.rings.integer import Integer 

 

args = ['integrate'] 

 

got_polynomial = True if polynomial is not None else False 

 

if got_polynomial: 

args.append('--valuation=integrate') 

else: 

args.append('--valuation=volume') 

 

if algorithm=='triangulate': 

args.append('--triangulate') 

elif algorithm=='cone-decompose': 

args.append('--cone-decompose') 

 

if 'redundancy_check' not in kwds: 

args.append('--redundancy-check=none') 

 

for key,value in kwds.items(): 

if value is None or value is False: 

continue 

 

key = key.replace('_','-') 

if value is True: 

args.append('--{}'.format(key)) 

else: 

args.append('--{}={}'.format(key, value)) 

 

if got_polynomial: 

if not isinstance(polynomial, six.string_types): 

# transform polynomial to LattE description 

monomials_list = to_latte_polynomial(polynomial) 

else: 

monomials_list = str(polynomial) 

 

from sage.misc.temporary_file import tmp_filename 

filename_polynomial = tmp_filename() 

 

with open(filename_polynomial, 'w') as f: 

f.write(monomials_list) 

args += ['--monomials=' + filename_polynomial] 

 

args += ['/dev/stdin'] 

 

try: 

# The cwd argument is needed because latte 

# always produces diagnostic output files. 

latte_proc = Popen(args, 

stdin=PIPE, stdout=PIPE, 

stderr=(None if verbose else PIPE), 

cwd=str(SAGE_TMP)) 

except OSError: 

from sage.misc.package import PackageNotFoundError 

raise PackageNotFoundError('latte_int') 

 

ans, err = latte_proc.communicate(arg) 

ret_code = latte_proc.poll() 

if ret_code: 

if err is None: 

err = ", see error message above" 

else: 

err = ":\n" + err 

raise RuntimeError("LattE integrale program failed (exit code {})".format(ret_code) + err.strip()) 

 

ans = ans.splitlines() 

ans = ans[-5].split() 

assert(ans[0]=='Answer:') 

ans = ans[1] 

 

if raw_output: 

return ans 

else: 

from sage.rings.rational import Rational 

return Rational(ans) 

 

def to_latte_polynomial(polynomial): 

r""" 

Helper function to transform a polynomial to its LattE description. 

 

INPUT: 

 

- ``polynomial`` -- a multivariate polynomial. 

 

OUTPUT: 

 

A string that describes the monomials list and exponent vectors. 

 

TESTS:: 

 

Testing a polynomial in three variables:: 

 

sage: from sage.interfaces.latte import to_latte_polynomial 

sage: x, y, z = polygens(QQ, 'x, y, z') 

sage: f = 3*x^2*y^4*z^6 + 7*y^3*z^5 

sage: to_latte_polynomial(f) 

'[[3, [2, 4, 6]], [7, [0, 3, 5]]]' 

 

Testing a univariate polynomial:: 

 

sage: x = polygen(QQ, 'x') 

sage: to_latte_polynomial((x-1)^2) 

'[[1, [0]], [-2, [1]], [1, [2]]]' 

""" 

from sage.rings.polynomial.polydict import ETuple 

 

coefficients_list = polynomial.coefficients() 

 

# transform list of exponents into a list of lists. 

# this branch handles the multivariate/univariate case 

if isinstance(polynomial.exponents()[0], ETuple): 

exponents_list = [list(exponent_vector_i) for exponent_vector_i in polynomial.exponents()] 

else: 

exponents_list = [[exponent_vector_i] for exponent_vector_i in polynomial.exponents()] 

 

# assuming that the order in coefficients() and exponents() methods match 

monomials_list = zip(coefficients_list, exponents_list) 

monomials_list = [list(monomial_i) for monomial_i in monomials_list] 

monomials_list = str(monomials_list) 

 

return monomials_list