Coverage for /usr/lib/python3/dist-packages/sympy/combinatorics/permutations.py: 24%

792 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

1import random 

2from collections import defaultdict 

3from collections.abc import Iterable 

4from functools import reduce 

5 

6from sympy.core.parameters import global_parameters 

7from sympy.core.basic import Atom 

8from sympy.core.expr import Expr 

9from sympy.core.numbers import Integer 

10from sympy.core.sympify import _sympify 

11from sympy.matrices import zeros 

12from sympy.polys.polytools import lcm 

13from sympy.printing.repr import srepr 

14from sympy.utilities.iterables import (flatten, has_variety, minlex, 

15 has_dups, runs, is_sequence) 

16from sympy.utilities.misc import as_int 

17from mpmath.libmp.libintmath import ifac 

18from sympy.multipledispatch import dispatch 

19 

20def _af_rmul(a, b): 

21 """ 

22 Return the product b*a; input and output are array forms. The ith value 

23 is a[b[i]]. 

24 

25 Examples 

26 ======== 

27 

28 >>> from sympy.combinatorics.permutations import _af_rmul, Permutation 

29 

30 >>> a, b = [1, 0, 2], [0, 2, 1] 

31 >>> _af_rmul(a, b) 

32 [1, 2, 0] 

33 >>> [a[b[i]] for i in range(3)] 

34 [1, 2, 0] 

35 

36 This handles the operands in reverse order compared to the ``*`` operator: 

37 

38 >>> a = Permutation(a) 

39 >>> b = Permutation(b) 

40 >>> list(a*b) 

41 [2, 0, 1] 

42 >>> [b(a(i)) for i in range(3)] 

43 [2, 0, 1] 

44 

45 See Also 

46 ======== 

47 

48 rmul, _af_rmuln 

49 """ 

50 return [a[i] for i in b] 

51 

52 

53def _af_rmuln(*abc): 

54 """ 

55 Given [a, b, c, ...] return the product of ...*c*b*a using array forms. 

56 The ith value is a[b[c[i]]]. 

57 

58 Examples 

59 ======== 

60 

61 >>> from sympy.combinatorics.permutations import _af_rmul, Permutation 

62 

63 >>> a, b = [1, 0, 2], [0, 2, 1] 

64 >>> _af_rmul(a, b) 

65 [1, 2, 0] 

66 >>> [a[b[i]] for i in range(3)] 

67 [1, 2, 0] 

68 

69 This handles the operands in reverse order compared to the ``*`` operator: 

70 

71 >>> a = Permutation(a); b = Permutation(b) 

72 >>> list(a*b) 

73 [2, 0, 1] 

74 >>> [b(a(i)) for i in range(3)] 

75 [2, 0, 1] 

76 

77 See Also 

78 ======== 

79 

80 rmul, _af_rmul 

81 """ 

82 a = abc 

83 m = len(a) 

84 if m == 3: 

85 p0, p1, p2 = a 

86 return [p0[p1[i]] for i in p2] 

87 if m == 4: 

88 p0, p1, p2, p3 = a 

89 return [p0[p1[p2[i]]] for i in p3] 

90 if m == 5: 

91 p0, p1, p2, p3, p4 = a 

92 return [p0[p1[p2[p3[i]]]] for i in p4] 

93 if m == 6: 

94 p0, p1, p2, p3, p4, p5 = a 

95 return [p0[p1[p2[p3[p4[i]]]]] for i in p5] 

96 if m == 7: 

97 p0, p1, p2, p3, p4, p5, p6 = a 

98 return [p0[p1[p2[p3[p4[p5[i]]]]]] for i in p6] 

99 if m == 8: 

100 p0, p1, p2, p3, p4, p5, p6, p7 = a 

101 return [p0[p1[p2[p3[p4[p5[p6[i]]]]]]] for i in p7] 

102 if m == 1: 

103 return a[0][:] 

104 if m == 2: 

105 a, b = a 

106 return [a[i] for i in b] 

107 if m == 0: 

108 raise ValueError("String must not be empty") 

109 p0 = _af_rmuln(*a[:m//2]) 

110 p1 = _af_rmuln(*a[m//2:]) 

111 return [p0[i] for i in p1] 

112 

113 

114def _af_parity(pi): 

115 """ 

116 Computes the parity of a permutation in array form. 

117 

118 Explanation 

119 =========== 

120 

121 The parity of a permutation reflects the parity of the 

122 number of inversions in the permutation, i.e., the 

123 number of pairs of x and y such that x > y but p[x] < p[y]. 

124 

125 Examples 

126 ======== 

127 

128 >>> from sympy.combinatorics.permutations import _af_parity 

129 >>> _af_parity([0, 1, 2, 3]) 

130 0 

131 >>> _af_parity([3, 2, 0, 1]) 

132 1 

133 

134 See Also 

135 ======== 

136 

137 Permutation 

138 """ 

139 n = len(pi) 

140 a = [0] * n 

141 c = 0 

142 for j in range(n): 

143 if a[j] == 0: 

144 c += 1 

145 a[j] = 1 

146 i = j 

147 while pi[i] != j: 

148 i = pi[i] 

149 a[i] = 1 

150 return (n - c) % 2 

151 

152 

153def _af_invert(a): 

154 """ 

155 Finds the inverse, ~A, of a permutation, A, given in array form. 

156 

157 Examples 

158 ======== 

159 

160 >>> from sympy.combinatorics.permutations import _af_invert, _af_rmul 

161 >>> A = [1, 2, 0, 3] 

162 >>> _af_invert(A) 

163 [2, 0, 1, 3] 

164 >>> _af_rmul(_, A) 

165 [0, 1, 2, 3] 

166 

167 See Also 

168 ======== 

169 

170 Permutation, __invert__ 

171 """ 

172 inv_form = [0] * len(a) 

173 for i, ai in enumerate(a): 

174 inv_form[ai] = i 

175 return inv_form 

176 

177 

178def _af_pow(a, n): 

179 """ 

180 Routine for finding powers of a permutation. 

181 

182 Examples 

183 ======== 

184 

185 >>> from sympy.combinatorics import Permutation 

186 >>> from sympy.combinatorics.permutations import _af_pow 

187 >>> p = Permutation([2, 0, 3, 1]) 

188 >>> p.order() 

189 4 

190 >>> _af_pow(p._array_form, 4) 

191 [0, 1, 2, 3] 

192 """ 

193 if n == 0: 

194 return list(range(len(a))) 

195 if n < 0: 

196 return _af_pow(_af_invert(a), -n) 

197 if n == 1: 

198 return a[:] 

199 elif n == 2: 

200 b = [a[i] for i in a] 

201 elif n == 3: 

202 b = [a[a[i]] for i in a] 

203 elif n == 4: 

204 b = [a[a[a[i]]] for i in a] 

205 else: 

206 # use binary multiplication 

207 b = list(range(len(a))) 

208 while 1: 

209 if n & 1: 

210 b = [b[i] for i in a] 

211 n -= 1 

212 if not n: 

213 break 

214 if n % 4 == 0: 

215 a = [a[a[a[i]]] for i in a] 

216 n = n // 4 

217 elif n % 2 == 0: 

218 a = [a[i] for i in a] 

219 n = n // 2 

220 return b 

221 

222 

223def _af_commutes_with(a, b): 

224 """ 

225 Checks if the two permutations with array forms 

226 given by ``a`` and ``b`` commute. 

227 

228 Examples 

229 ======== 

230 

231 >>> from sympy.combinatorics.permutations import _af_commutes_with 

232 >>> _af_commutes_with([1, 2, 0], [0, 2, 1]) 

233 False 

234 

235 See Also 

236 ======== 

237 

238 Permutation, commutes_with 

239 """ 

240 return not any(a[b[i]] != b[a[i]] for i in range(len(a) - 1)) 

241 

242 

243class Cycle(dict): 

244 """ 

245 Wrapper around dict which provides the functionality of a disjoint cycle. 

246 

247 Explanation 

248 =========== 

249 

250 A cycle shows the rule to use to move subsets of elements to obtain 

251 a permutation. The Cycle class is more flexible than Permutation in 

252 that 1) all elements need not be present in order to investigate how 

253 multiple cycles act in sequence and 2) it can contain singletons: 

254 

255 >>> from sympy.combinatorics.permutations import Perm, Cycle 

256 

257 A Cycle will automatically parse a cycle given as a tuple on the rhs: 

258 

259 >>> Cycle(1, 2)(2, 3) 

260 (1 3 2) 

261 

262 The identity cycle, Cycle(), can be used to start a product: 

263 

264 >>> Cycle()(1, 2)(2, 3) 

265 (1 3 2) 

266 

267 The array form of a Cycle can be obtained by calling the list 

268 method (or passing it to the list function) and all elements from 

269 0 will be shown: 

270 

271 >>> a = Cycle(1, 2) 

272 >>> a.list() 

273 [0, 2, 1] 

274 >>> list(a) 

275 [0, 2, 1] 

276 

277 If a larger (or smaller) range is desired use the list method and 

278 provide the desired size -- but the Cycle cannot be truncated to 

279 a size smaller than the largest element that is out of place: 

280 

281 >>> b = Cycle(2, 4)(1, 2)(3, 1, 4)(1, 3) 

282 >>> b.list() 

283 [0, 2, 1, 3, 4] 

284 >>> b.list(b.size + 1) 

285 [0, 2, 1, 3, 4, 5] 

286 >>> b.list(-1) 

287 [0, 2, 1] 

288 

289 Singletons are not shown when printing with one exception: the largest 

290 element is always shown -- as a singleton if necessary: 

291 

292 >>> Cycle(1, 4, 10)(4, 5) 

293 (1 5 4 10) 

294 >>> Cycle(1, 2)(4)(5)(10) 

295 (1 2)(10) 

296 

297 The array form can be used to instantiate a Permutation so other 

298 properties of the permutation can be investigated: 

299 

300 >>> Perm(Cycle(1, 2)(3, 4).list()).transpositions() 

301 [(1, 2), (3, 4)] 

302 

303 Notes 

304 ===== 

305 

306 The underlying structure of the Cycle is a dictionary and although 

307 the __iter__ method has been redefined to give the array form of the 

308 cycle, the underlying dictionary items are still available with the 

309 such methods as items(): 

310 

311 >>> list(Cycle(1, 2).items()) 

312 [(1, 2), (2, 1)] 

313 

314 See Also 

315 ======== 

316 

317 Permutation 

318 """ 

319 def __missing__(self, arg): 

320 """Enter arg into dictionary and return arg.""" 

321 return as_int(arg) 

322 

323 def __iter__(self): 

324 yield from self.list() 

325 

326 def __call__(self, *other): 

327 """Return product of cycles processed from R to L. 

328 

329 Examples 

330 ======== 

331 

332 >>> from sympy.combinatorics import Cycle 

333 >>> Cycle(1, 2)(2, 3) 

334 (1 3 2) 

335 

336 An instance of a Cycle will automatically parse list-like 

337 objects and Permutations that are on the right. It is more 

338 flexible than the Permutation in that all elements need not 

339 be present: 

340 

341 >>> a = Cycle(1, 2) 

342 >>> a(2, 3) 

343 (1 3 2) 

344 >>> a(2, 3)(4, 5) 

345 (1 3 2)(4 5) 

346 

347 """ 

348 rv = Cycle(*other) 

349 for k, v in zip(list(self.keys()), [rv[self[k]] for k in self.keys()]): 

350 rv[k] = v 

351 return rv 

352 

353 def list(self, size=None): 

354 """Return the cycles as an explicit list starting from 0 up 

355 to the greater of the largest value in the cycles and size. 

356 

357 Truncation of trailing unmoved items will occur when size 

358 is less than the maximum element in the cycle; if this is 

359 desired, setting ``size=-1`` will guarantee such trimming. 

360 

361 Examples 

362 ======== 

363 

364 >>> from sympy.combinatorics import Cycle 

365 >>> p = Cycle(2, 3)(4, 5) 

366 >>> p.list() 

367 [0, 1, 3, 2, 5, 4] 

368 >>> p.list(10) 

369 [0, 1, 3, 2, 5, 4, 6, 7, 8, 9] 

370 

371 Passing a length too small will trim trailing, unchanged elements 

372 in the permutation: 

373 

374 >>> Cycle(2, 4)(1, 2, 4).list(-1) 

375 [0, 2, 1] 

376 """ 

377 if not self and size is None: 

378 raise ValueError('must give size for empty Cycle') 

379 if size is not None: 

380 big = max([i for i in self.keys() if self[i] != i] + [0]) 

381 size = max(size, big + 1) 

382 else: 

383 size = self.size 

384 return [self[i] for i in range(size)] 

385 

386 def __repr__(self): 

387 """We want it to print as a Cycle, not as a dict. 

388 

389 Examples 

390 ======== 

391 

392 >>> from sympy.combinatorics import Cycle 

393 >>> Cycle(1, 2) 

394 (1 2) 

395 >>> print(_) 

396 (1 2) 

397 >>> list(Cycle(1, 2).items()) 

398 [(1, 2), (2, 1)] 

399 """ 

400 if not self: 

401 return 'Cycle()' 

402 cycles = Permutation(self).cyclic_form 

403 s = ''.join(str(tuple(c)) for c in cycles) 

404 big = self.size - 1 

405 if not any(i == big for c in cycles for i in c): 

406 s += '(%s)' % big 

407 return 'Cycle%s' % s 

408 

409 def __str__(self): 

410 """We want it to be printed in a Cycle notation with no 

411 comma in-between. 

412 

413 Examples 

414 ======== 

415 

416 >>> from sympy.combinatorics import Cycle 

417 >>> Cycle(1, 2) 

418 (1 2) 

419 >>> Cycle(1, 2, 4)(5, 6) 

420 (1 2 4)(5 6) 

421 """ 

422 if not self: 

423 return '()' 

424 cycles = Permutation(self).cyclic_form 

425 s = ''.join(str(tuple(c)) for c in cycles) 

426 big = self.size - 1 

427 if not any(i == big for c in cycles for i in c): 

428 s += '(%s)' % big 

429 s = s.replace(',', '') 

430 return s 

431 

432 def __init__(self, *args): 

433 """Load up a Cycle instance with the values for the cycle. 

434 

435 Examples 

436 ======== 

437 

438 >>> from sympy.combinatorics import Cycle 

439 >>> Cycle(1, 2, 6) 

440 (1 2 6) 

441 """ 

442 

443 if not args: 

444 return 

445 if len(args) == 1: 

446 if isinstance(args[0], Permutation): 

447 for c in args[0].cyclic_form: 

448 self.update(self(*c)) 

449 return 

450 elif isinstance(args[0], Cycle): 

451 for k, v in args[0].items(): 

452 self[k] = v 

453 return 

454 args = [as_int(a) for a in args] 

455 if any(i < 0 for i in args): 

456 raise ValueError('negative integers are not allowed in a cycle.') 

457 if has_dups(args): 

458 raise ValueError('All elements must be unique in a cycle.') 

459 for i in range(-len(args), 0): 

460 self[args[i]] = args[i + 1] 

461 

462 @property 

463 def size(self): 

464 if not self: 

465 return 0 

466 return max(self.keys()) + 1 

467 

468 def copy(self): 

469 return Cycle(self) 

470 

471 

472class Permutation(Atom): 

473 r""" 

474 A permutation, alternatively known as an 'arrangement number' or 'ordering' 

475 is an arrangement of the elements of an ordered list into a one-to-one 

476 mapping with itself. The permutation of a given arrangement is given by 

477 indicating the positions of the elements after re-arrangement [2]_. For 

478 example, if one started with elements ``[x, y, a, b]`` (in that order) and 

479 they were reordered as ``[x, y, b, a]`` then the permutation would be 

480 ``[0, 1, 3, 2]``. Notice that (in SymPy) the first element is always referred 

481 to as 0 and the permutation uses the indices of the elements in the 

482 original ordering, not the elements ``(a, b, ...)`` themselves. 

483 

484 >>> from sympy.combinatorics import Permutation 

485 >>> from sympy import init_printing 

486 >>> init_printing(perm_cyclic=False, pretty_print=False) 

487 

488 Permutations Notation 

489 ===================== 

490 

491 Permutations are commonly represented in disjoint cycle or array forms. 

492 

493 Array Notation and 2-line Form 

494 ------------------------------------ 

495 

496 In the 2-line form, the elements and their final positions are shown 

497 as a matrix with 2 rows: 

498 

499 [0 1 2 ... n-1] 

500 [p(0) p(1) p(2) ... p(n-1)] 

501 

502 Since the first line is always ``range(n)``, where n is the size of p, 

503 it is sufficient to represent the permutation by the second line, 

504 referred to as the "array form" of the permutation. This is entered 

505 in brackets as the argument to the Permutation class: 

506 

507 >>> p = Permutation([0, 2, 1]); p 

508 Permutation([0, 2, 1]) 

509 

510 Given i in range(p.size), the permutation maps i to i^p 

511 

512 >>> [i^p for i in range(p.size)] 

513 [0, 2, 1] 

514 

515 The composite of two permutations p*q means first apply p, then q, so 

516 i^(p*q) = (i^p)^q which is i^p^q according to Python precedence rules: 

517 

518 >>> q = Permutation([2, 1, 0]) 

519 >>> [i^p^q for i in range(3)] 

520 [2, 0, 1] 

521 >>> [i^(p*q) for i in range(3)] 

522 [2, 0, 1] 

523 

524 One can use also the notation p(i) = i^p, but then the composition 

525 rule is (p*q)(i) = q(p(i)), not p(q(i)): 

526 

527 >>> [(p*q)(i) for i in range(p.size)] 

528 [2, 0, 1] 

529 >>> [q(p(i)) for i in range(p.size)] 

530 [2, 0, 1] 

531 >>> [p(q(i)) for i in range(p.size)] 

532 [1, 2, 0] 

533 

534 Disjoint Cycle Notation 

535 ----------------------- 

536 

537 In disjoint cycle notation, only the elements that have shifted are 

538 indicated. 

539 

540 For example, [1, 3, 2, 0] can be represented as (0, 1, 3)(2). 

541 This can be understood from the 2 line format of the given permutation. 

542 In the 2-line form, 

543 [0 1 2 3] 

544 [1 3 2 0] 

545 

546 The element in the 0th position is 1, so 0 -> 1. The element in the 1st 

547 position is three, so 1 -> 3. And the element in the third position is again 

548 0, so 3 -> 0. Thus, 0 -> 1 -> 3 -> 0, and 2 -> 2. Thus, this can be represented 

549 as 2 cycles: (0, 1, 3)(2). 

550 In common notation, singular cycles are not explicitly written as they can be 

551 inferred implicitly. 

552 

553 Only the relative ordering of elements in a cycle matter: 

554 

555 >>> Permutation(1,2,3) == Permutation(2,3,1) == Permutation(3,1,2) 

556 True 

557 

558 The disjoint cycle notation is convenient when representing 

559 permutations that have several cycles in them: 

560 

561 >>> Permutation(1, 2)(3, 5) == Permutation([[1, 2], [3, 5]]) 

562 True 

563 

564 It also provides some economy in entry when computing products of 

565 permutations that are written in disjoint cycle notation: 

566 

567 >>> Permutation(1, 2)(1, 3)(2, 3) 

568 Permutation([0, 3, 2, 1]) 

569 >>> _ == Permutation([[1, 2]])*Permutation([[1, 3]])*Permutation([[2, 3]]) 

570 True 

571 

572 Caution: when the cycles have common elements between them then the order 

573 in which the permutations are applied matters. This module applies 

574 the permutations from *left to right*. 

575 

576 >>> Permutation(1, 2)(2, 3) == Permutation([(1, 2), (2, 3)]) 

577 True 

578 >>> Permutation(1, 2)(2, 3).list() 

579 [0, 3, 1, 2] 

580 

581 In the above case, (1,2) is computed before (2,3). 

582 As 0 -> 0, 0 -> 0, element in position 0 is 0. 

583 As 1 -> 2, 2 -> 3, element in position 1 is 3. 

584 As 2 -> 1, 1 -> 1, element in position 2 is 1. 

585 As 3 -> 3, 3 -> 2, element in position 3 is 2. 

586 

587 If the first and second elements had been 

588 swapped first, followed by the swapping of the second 

589 and third, the result would have been [0, 2, 3, 1]. 

590 If, you want to apply the cycles in the conventional 

591 right to left order, call the function with arguments in reverse order 

592 as demonstrated below: 

593 

594 >>> Permutation([(1, 2), (2, 3)][::-1]).list() 

595 [0, 2, 3, 1] 

596 

597 Entering a singleton in a permutation is a way to indicate the size of the 

598 permutation. The ``size`` keyword can also be used. 

599 

600 Array-form entry: 

601 

602 >>> Permutation([[1, 2], [9]]) 

603 Permutation([0, 2, 1], size=10) 

604 >>> Permutation([[1, 2]], size=10) 

605 Permutation([0, 2, 1], size=10) 

606 

607 Cyclic-form entry: 

608 

609 >>> Permutation(1, 2, size=10) 

610 Permutation([0, 2, 1], size=10) 

611 >>> Permutation(9)(1, 2) 

612 Permutation([0, 2, 1], size=10) 

613 

614 Caution: no singleton containing an element larger than the largest 

615 in any previous cycle can be entered. This is an important difference 

616 in how Permutation and Cycle handle the ``__call__`` syntax. A singleton 

617 argument at the start of a Permutation performs instantiation of the 

618 Permutation and is permitted: 

619 

620 >>> Permutation(5) 

621 Permutation([], size=6) 

622 

623 A singleton entered after instantiation is a call to the permutation 

624 -- a function call -- and if the argument is out of range it will 

625 trigger an error. For this reason, it is better to start the cycle 

626 with the singleton: 

627 

628 The following fails because there is no element 3: 

629 

630 >>> Permutation(1, 2)(3) 

631 Traceback (most recent call last): 

632 ... 

633 IndexError: list index out of range 

634 

635 This is ok: only the call to an out of range singleton is prohibited; 

636 otherwise the permutation autosizes: 

637 

638 >>> Permutation(3)(1, 2) 

639 Permutation([0, 2, 1, 3]) 

640 >>> Permutation(1, 2)(3, 4) == Permutation(3, 4)(1, 2) 

641 True 

642 

643 

644 Equality testing 

645 ---------------- 

646 

647 The array forms must be the same in order for permutations to be equal: 

648 

649 >>> Permutation([1, 0, 2, 3]) == Permutation([1, 0]) 

650 False 

651 

652 

653 Identity Permutation 

654 -------------------- 

655 

656 The identity permutation is a permutation in which no element is out of 

657 place. It can be entered in a variety of ways. All the following create 

658 an identity permutation of size 4: 

659 

660 >>> I = Permutation([0, 1, 2, 3]) 

661 >>> all(p == I for p in [ 

662 ... Permutation(3), 

663 ... Permutation(range(4)), 

664 ... Permutation([], size=4), 

665 ... Permutation(size=4)]) 

666 True 

667 

668 Watch out for entering the range *inside* a set of brackets (which is 

669 cycle notation): 

670 

671 >>> I == Permutation([range(4)]) 

672 False 

673 

674 

675 Permutation Printing 

676 ==================== 

677 

678 There are a few things to note about how Permutations are printed. 

679 

680 .. deprecated:: 1.6 

681 

682 Configuring Permutation printing by setting 

683 ``Permutation.print_cyclic`` is deprecated. Users should use the 

684 ``perm_cyclic`` flag to the printers, as described below. 

685 

686 1) If you prefer one form (array or cycle) over another, you can set 

687 ``init_printing`` with the ``perm_cyclic`` flag. 

688 

689 >>> from sympy import init_printing 

690 >>> p = Permutation(1, 2)(4, 5)(3, 4) 

691 >>> p 

692 Permutation([0, 2, 1, 4, 5, 3]) 

693 

694 >>> init_printing(perm_cyclic=True, pretty_print=False) 

695 >>> p 

696 (1 2)(3 4 5) 

697 

698 2) Regardless of the setting, a list of elements in the array for cyclic 

699 form can be obtained and either of those can be copied and supplied as 

700 the argument to Permutation: 

701 

702 >>> p.array_form 

703 [0, 2, 1, 4, 5, 3] 

704 >>> p.cyclic_form 

705 [[1, 2], [3, 4, 5]] 

706 >>> Permutation(_) == p 

707 True 

708 

709 3) Printing is economical in that as little as possible is printed while 

710 retaining all information about the size of the permutation: 

711 

712 >>> init_printing(perm_cyclic=False, pretty_print=False) 

713 >>> Permutation([1, 0, 2, 3]) 

714 Permutation([1, 0, 2, 3]) 

715 >>> Permutation([1, 0, 2, 3], size=20) 

716 Permutation([1, 0], size=20) 

717 >>> Permutation([1, 0, 2, 4, 3, 5, 6], size=20) 

718 Permutation([1, 0, 2, 4, 3], size=20) 

719 

720 >>> p = Permutation([1, 0, 2, 3]) 

721 >>> init_printing(perm_cyclic=True, pretty_print=False) 

722 >>> p 

723 (3)(0 1) 

724 >>> init_printing(perm_cyclic=False, pretty_print=False) 

725 

726 The 2 was not printed but it is still there as can be seen with the 

727 array_form and size methods: 

728 

729 >>> p.array_form 

730 [1, 0, 2, 3] 

731 >>> p.size 

732 4 

733 

734 Short introduction to other methods 

735 =================================== 

736 

737 The permutation can act as a bijective function, telling what element is 

738 located at a given position 

739 

740 >>> q = Permutation([5, 2, 3, 4, 1, 0]) 

741 >>> q.array_form[1] # the hard way 

742 2 

743 >>> q(1) # the easy way 

744 2 

745 >>> {i: q(i) for i in range(q.size)} # showing the bijection 

746 {0: 5, 1: 2, 2: 3, 3: 4, 4: 1, 5: 0} 

747 

748 The full cyclic form (including singletons) can be obtained: 

749 

750 >>> p.full_cyclic_form 

751 [[0, 1], [2], [3]] 

752 

753 Any permutation can be factored into transpositions of pairs of elements: 

754 

755 >>> Permutation([[1, 2], [3, 4, 5]]).transpositions() 

756 [(1, 2), (3, 5), (3, 4)] 

757 >>> Permutation.rmul(*[Permutation([ti], size=6) for ti in _]).cyclic_form 

758 [[1, 2], [3, 4, 5]] 

759 

760 The number of permutations on a set of n elements is given by n! and is 

761 called the cardinality. 

762 

763 >>> p.size 

764 4 

765 >>> p.cardinality 

766 24 

767 

768 A given permutation has a rank among all the possible permutations of the 

769 same elements, but what that rank is depends on how the permutations are 

770 enumerated. (There are a number of different methods of doing so.) The 

771 lexicographic rank is given by the rank method and this rank is used to 

772 increment a permutation with addition/subtraction: 

773 

774 >>> p.rank() 

775 6 

776 >>> p + 1 

777 Permutation([1, 0, 3, 2]) 

778 >>> p.next_lex() 

779 Permutation([1, 0, 3, 2]) 

780 >>> _.rank() 

781 7 

782 >>> p.unrank_lex(p.size, rank=7) 

783 Permutation([1, 0, 3, 2]) 

784 

785 The product of two permutations p and q is defined as their composition as 

786 functions, (p*q)(i) = q(p(i)) [6]_. 

787 

788 >>> p = Permutation([1, 0, 2, 3]) 

789 >>> q = Permutation([2, 3, 1, 0]) 

790 >>> list(q*p) 

791 [2, 3, 0, 1] 

792 >>> list(p*q) 

793 [3, 2, 1, 0] 

794 >>> [q(p(i)) for i in range(p.size)] 

795 [3, 2, 1, 0] 

796 

797 The permutation can be 'applied' to any list-like object, not only 

798 Permutations: 

799 

800 >>> p(['zero', 'one', 'four', 'two']) 

801 ['one', 'zero', 'four', 'two'] 

802 >>> p('zo42') 

803 ['o', 'z', '4', '2'] 

804 

805 If you have a list of arbitrary elements, the corresponding permutation 

806 can be found with the from_sequence method: 

807 

808 >>> Permutation.from_sequence('SymPy') 

809 Permutation([1, 3, 2, 0, 4]) 

810 

811 Checking if a Permutation is contained in a Group 

812 ================================================= 

813 

814 Generally if you have a group of permutations G on n symbols, and 

815 you're checking if a permutation on less than n symbols is part 

816 of that group, the check will fail. 

817 

818 Here is an example for n=5 and we check if the cycle 

819 (1,2,3) is in G: 

820 

821 >>> from sympy import init_printing 

822 >>> init_printing(perm_cyclic=True, pretty_print=False) 

823 >>> from sympy.combinatorics import Cycle, Permutation 

824 >>> from sympy.combinatorics.perm_groups import PermutationGroup 

825 >>> G = PermutationGroup(Cycle(2, 3)(4, 5), Cycle(1, 2, 3, 4, 5)) 

826 >>> p1 = Permutation(Cycle(2, 5, 3)) 

827 >>> p2 = Permutation(Cycle(1, 2, 3)) 

828 >>> a1 = Permutation(Cycle(1, 2, 3).list(6)) 

829 >>> a2 = Permutation(Cycle(1, 2, 3)(5)) 

830 >>> a3 = Permutation(Cycle(1, 2, 3),size=6) 

831 >>> for p in [p1,p2,a1,a2,a3]: p, G.contains(p) 

832 ((2 5 3), True) 

833 ((1 2 3), False) 

834 ((5)(1 2 3), True) 

835 ((5)(1 2 3), True) 

836 ((5)(1 2 3), True) 

837 

838 The check for p2 above will fail. 

839 

840 Checking if p1 is in G works because SymPy knows 

841 G is a group on 5 symbols, and p1 is also on 5 symbols 

842 (its largest element is 5). 

843 

844 For ``a1``, the ``.list(6)`` call will extend the permutation to 5 

845 symbols, so the test will work as well. In the case of ``a2`` the 

846 permutation is being extended to 5 symbols by using a singleton, 

847 and in the case of ``a3`` it's extended through the constructor 

848 argument ``size=6``. 

849 

850 There is another way to do this, which is to tell the ``contains`` 

851 method that the number of symbols the group is on does not need to 

852 match perfectly the number of symbols for the permutation: 

853 

854 >>> G.contains(p2,strict=False) 

855 True 

856 

857 This can be via the ``strict`` argument to the ``contains`` method, 

858 and SymPy will try to extend the permutation on its own and then 

859 perform the containment check. 

860 

861 See Also 

862 ======== 

863 

864 Cycle 

865 

866 References 

867 ========== 

868 

869 .. [1] Skiena, S. 'Permutations.' 1.1 in Implementing Discrete Mathematics 

870 Combinatorics and Graph Theory with Mathematica. Reading, MA: 

871 Addison-Wesley, pp. 3-16, 1990. 

872 

873 .. [2] Knuth, D. E. The Art of Computer Programming, Vol. 4: Combinatorial 

874 Algorithms, 1st ed. Reading, MA: Addison-Wesley, 2011. 

875 

876 .. [3] Wendy Myrvold and Frank Ruskey. 2001. Ranking and unranking 

877 permutations in linear time. Inf. Process. Lett. 79, 6 (September 2001), 

878 281-284. DOI=10.1016/S0020-0190(01)00141-7 

879 

880 .. [4] D. L. Kreher, D. R. Stinson 'Combinatorial Algorithms' 

881 CRC Press, 1999 

882 

883 .. [5] Graham, R. L.; Knuth, D. E.; and Patashnik, O. 

884 Concrete Mathematics: A Foundation for Computer Science, 2nd ed. 

885 Reading, MA: Addison-Wesley, 1994. 

886 

887 .. [6] https://en.wikipedia.org/w/index.php?oldid=499948155#Product_and_inverse 

888 

889 .. [7] https://en.wikipedia.org/wiki/Lehmer_code 

890 

891 """ 

892 

893 is_Permutation = True 

894 

895 _array_form = None 

896 _cyclic_form = None 

897 _cycle_structure = None 

898 _size = None 

899 _rank = None 

900 

901 def __new__(cls, *args, size=None, **kwargs): 

902 """ 

903 Constructor for the Permutation object from a list or a 

904 list of lists in which all elements of the permutation may 

905 appear only once. 

906 

907 Examples 

908 ======== 

909 

910 >>> from sympy.combinatorics import Permutation 

911 >>> from sympy import init_printing 

912 >>> init_printing(perm_cyclic=False, pretty_print=False) 

913 

914 Permutations entered in array-form are left unaltered: 

915 

916 >>> Permutation([0, 2, 1]) 

917 Permutation([0, 2, 1]) 

918 

919 Permutations entered in cyclic form are converted to array form; 

920 singletons need not be entered, but can be entered to indicate the 

921 largest element: 

922 

923 >>> Permutation([[4, 5, 6], [0, 1]]) 

924 Permutation([1, 0, 2, 3, 5, 6, 4]) 

925 >>> Permutation([[4, 5, 6], [0, 1], [19]]) 

926 Permutation([1, 0, 2, 3, 5, 6, 4], size=20) 

927 

928 All manipulation of permutations assumes that the smallest element 

929 is 0 (in keeping with 0-based indexing in Python) so if the 0 is 

930 missing when entering a permutation in array form, an error will be 

931 raised: 

932 

933 >>> Permutation([2, 1]) 

934 Traceback (most recent call last): 

935 ... 

936 ValueError: Integers 0 through 2 must be present. 

937 

938 If a permutation is entered in cyclic form, it can be entered without 

939 singletons and the ``size`` specified so those values can be filled 

940 in, otherwise the array form will only extend to the maximum value 

941 in the cycles: 

942 

943 >>> Permutation([[1, 4], [3, 5, 2]], size=10) 

944 Permutation([0, 4, 3, 5, 1, 2], size=10) 

945 >>> _.array_form 

946 [0, 4, 3, 5, 1, 2, 6, 7, 8, 9] 

947 """ 

948 if size is not None: 

949 size = int(size) 

950 

951 #a) () 

952 #b) (1) = identity 

953 #c) (1, 2) = cycle 

954 #d) ([1, 2, 3]) = array form 

955 #e) ([[1, 2]]) = cyclic form 

956 #f) (Cycle) = conversion to permutation 

957 #g) (Permutation) = adjust size or return copy 

958 ok = True 

959 if not args: # a 

960 return cls._af_new(list(range(size or 0))) 

961 elif len(args) > 1: # c 

962 return cls._af_new(Cycle(*args).list(size)) 

963 if len(args) == 1: 

964 a = args[0] 

965 if isinstance(a, cls): # g 

966 if size is None or size == a.size: 

967 return a 

968 return cls(a.array_form, size=size) 

969 if isinstance(a, Cycle): # f 

970 return cls._af_new(a.list(size)) 

971 if not is_sequence(a): # b 

972 if size is not None and a + 1 > size: 

973 raise ValueError('size is too small when max is %s' % a) 

974 return cls._af_new(list(range(a + 1))) 

975 if has_variety(is_sequence(ai) for ai in a): 

976 ok = False 

977 else: 

978 ok = False 

979 if not ok: 

980 raise ValueError("Permutation argument must be a list of ints, " 

981 "a list of lists, Permutation or Cycle.") 

982 

983 # safe to assume args are valid; this also makes a copy 

984 # of the args 

985 args = list(args[0]) 

986 

987 is_cycle = args and is_sequence(args[0]) 

988 if is_cycle: # e 

989 args = [[int(i) for i in c] for c in args] 

990 else: # d 

991 args = [int(i) for i in args] 

992 

993 # if there are n elements present, 0, 1, ..., n-1 should be present 

994 # unless a cycle notation has been provided. A 0 will be added 

995 # for convenience in case one wants to enter permutations where 

996 # counting starts from 1. 

997 

998 temp = flatten(args) 

999 if has_dups(temp) and not is_cycle: 

1000 raise ValueError('there were repeated elements.') 

1001 temp = set(temp) 

1002 

1003 if not is_cycle: 

1004 if temp != set(range(len(temp))): 

1005 raise ValueError('Integers 0 through %s must be present.' % 

1006 max(temp)) 

1007 if size is not None and temp and max(temp) + 1 > size: 

1008 raise ValueError('max element should not exceed %s' % (size - 1)) 

1009 

1010 if is_cycle: 

1011 # it's not necessarily canonical so we won't store 

1012 # it -- use the array form instead 

1013 c = Cycle() 

1014 for ci in args: 

1015 c = c(*ci) 

1016 aform = c.list() 

1017 else: 

1018 aform = list(args) 

1019 if size and size > len(aform): 

1020 # don't allow for truncation of permutation which 

1021 # might split a cycle and lead to an invalid aform 

1022 # but do allow the permutation size to be increased 

1023 aform.extend(list(range(len(aform), size))) 

1024 

1025 return cls._af_new(aform) 

1026 

1027 @classmethod 

1028 def _af_new(cls, perm): 

1029 """A method to produce a Permutation object from a list; 

1030 the list is bound to the _array_form attribute, so it must 

1031 not be modified; this method is meant for internal use only; 

1032 the list ``a`` is supposed to be generated as a temporary value 

1033 in a method, so p = Perm._af_new(a) is the only object 

1034 to hold a reference to ``a``:: 

1035 

1036 Examples 

1037 ======== 

1038 

1039 >>> from sympy.combinatorics.permutations import Perm 

1040 >>> from sympy import init_printing 

1041 >>> init_printing(perm_cyclic=False, pretty_print=False) 

1042 >>> a = [2, 1, 3, 0] 

1043 >>> p = Perm._af_new(a) 

1044 >>> p 

1045 Permutation([2, 1, 3, 0]) 

1046 

1047 """ 

1048 p = super().__new__(cls) 

1049 p._array_form = perm 

1050 p._size = len(perm) 

1051 return p 

1052 

1053 def _hashable_content(self): 

1054 # the array_form (a list) is the Permutation arg, so we need to 

1055 # return a tuple, instead 

1056 return tuple(self.array_form) 

1057 

1058 @property 

1059 def array_form(self): 

1060 """ 

1061 Return a copy of the attribute _array_form 

1062 Examples 

1063 ======== 

1064 

1065 >>> from sympy.combinatorics import Permutation 

1066 >>> p = Permutation([[2, 0], [3, 1]]) 

1067 >>> p.array_form 

1068 [2, 3, 0, 1] 

1069 >>> Permutation([[2, 0, 3, 1]]).array_form 

1070 [3, 2, 0, 1] 

1071 >>> Permutation([2, 0, 3, 1]).array_form 

1072 [2, 0, 3, 1] 

1073 >>> Permutation([[1, 2], [4, 5]]).array_form 

1074 [0, 2, 1, 3, 5, 4] 

1075 """ 

1076 return self._array_form[:] 

1077 

1078 def list(self, size=None): 

1079 """Return the permutation as an explicit list, possibly 

1080 trimming unmoved elements if size is less than the maximum 

1081 element in the permutation; if this is desired, setting 

1082 ``size=-1`` will guarantee such trimming. 

1083 

1084 Examples 

1085 ======== 

1086 

1087 >>> from sympy.combinatorics import Permutation 

1088 >>> p = Permutation(2, 3)(4, 5) 

1089 >>> p.list() 

1090 [0, 1, 3, 2, 5, 4] 

1091 >>> p.list(10) 

1092 [0, 1, 3, 2, 5, 4, 6, 7, 8, 9] 

1093 

1094 Passing a length too small will trim trailing, unchanged elements 

1095 in the permutation: 

1096 

1097 >>> Permutation(2, 4)(1, 2, 4).list(-1) 

1098 [0, 2, 1] 

1099 >>> Permutation(3).list(-1) 

1100 [] 

1101 """ 

1102 if not self and size is None: 

1103 raise ValueError('must give size for empty Cycle') 

1104 rv = self.array_form 

1105 if size is not None: 

1106 if size > self.size: 

1107 rv.extend(list(range(self.size, size))) 

1108 else: 

1109 # find first value from rhs where rv[i] != i 

1110 i = self.size - 1 

1111 while rv: 

1112 if rv[-1] != i: 

1113 break 

1114 rv.pop() 

1115 i -= 1 

1116 return rv 

1117 

1118 @property 

1119 def cyclic_form(self): 

1120 """ 

1121 This is used to convert to the cyclic notation 

1122 from the canonical notation. Singletons are omitted. 

1123 

1124 Examples 

1125 ======== 

1126 

1127 >>> from sympy.combinatorics import Permutation 

1128 >>> p = Permutation([0, 3, 1, 2]) 

1129 >>> p.cyclic_form 

1130 [[1, 3, 2]] 

1131 >>> Permutation([1, 0, 2, 4, 3, 5]).cyclic_form 

1132 [[0, 1], [3, 4]] 

1133 

1134 See Also 

1135 ======== 

1136 

1137 array_form, full_cyclic_form 

1138 """ 

1139 if self._cyclic_form is not None: 

1140 return list(self._cyclic_form) 

1141 array_form = self.array_form 

1142 unchecked = [True] * len(array_form) 

1143 cyclic_form = [] 

1144 for i in range(len(array_form)): 

1145 if unchecked[i]: 

1146 cycle = [] 

1147 cycle.append(i) 

1148 unchecked[i] = False 

1149 j = i 

1150 while unchecked[array_form[j]]: 

1151 j = array_form[j] 

1152 cycle.append(j) 

1153 unchecked[j] = False 

1154 if len(cycle) > 1: 

1155 cyclic_form.append(cycle) 

1156 assert cycle == list(minlex(cycle)) 

1157 cyclic_form.sort() 

1158 self._cyclic_form = cyclic_form[:] 

1159 return cyclic_form 

1160 

1161 @property 

1162 def full_cyclic_form(self): 

1163 """Return permutation in cyclic form including singletons. 

1164 

1165 Examples 

1166 ======== 

1167 

1168 >>> from sympy.combinatorics import Permutation 

1169 >>> Permutation([0, 2, 1]).full_cyclic_form 

1170 [[0], [1, 2]] 

1171 """ 

1172 need = set(range(self.size)) - set(flatten(self.cyclic_form)) 

1173 rv = self.cyclic_form + [[i] for i in need] 

1174 rv.sort() 

1175 return rv 

1176 

1177 @property 

1178 def size(self): 

1179 """ 

1180 Returns the number of elements in the permutation. 

1181 

1182 Examples 

1183 ======== 

1184 

1185 >>> from sympy.combinatorics import Permutation 

1186 >>> Permutation([[3, 2], [0, 1]]).size 

1187 4 

1188 

1189 See Also 

1190 ======== 

1191 

1192 cardinality, length, order, rank 

1193 """ 

1194 return self._size 

1195 

1196 def support(self): 

1197 """Return the elements in permutation, P, for which P[i] != i. 

1198 

1199 Examples 

1200 ======== 

1201 

1202 >>> from sympy.combinatorics import Permutation 

1203 >>> p = Permutation([[3, 2], [0, 1], [4]]) 

1204 >>> p.array_form 

1205 [1, 0, 3, 2, 4] 

1206 >>> p.support() 

1207 [0, 1, 2, 3] 

1208 """ 

1209 a = self.array_form 

1210 return [i for i, e in enumerate(a) if a[i] != i] 

1211 

1212 def __add__(self, other): 

1213 """Return permutation that is other higher in rank than self. 

1214 

1215 The rank is the lexicographical rank, with the identity permutation 

1216 having rank of 0. 

1217 

1218 Examples 

1219 ======== 

1220 

1221 >>> from sympy.combinatorics import Permutation 

1222 >>> I = Permutation([0, 1, 2, 3]) 

1223 >>> a = Permutation([2, 1, 3, 0]) 

1224 >>> I + a.rank() == a 

1225 True 

1226 

1227 See Also 

1228 ======== 

1229 

1230 __sub__, inversion_vector 

1231 

1232 """ 

1233 rank = (self.rank() + other) % self.cardinality 

1234 rv = self.unrank_lex(self.size, rank) 

1235 rv._rank = rank 

1236 return rv 

1237 

1238 def __sub__(self, other): 

1239 """Return the permutation that is other lower in rank than self. 

1240 

1241 See Also 

1242 ======== 

1243 

1244 __add__ 

1245 """ 

1246 return self.__add__(-other) 

1247 

1248 @staticmethod 

1249 def rmul(*args): 

1250 """ 

1251 Return product of Permutations [a, b, c, ...] as the Permutation whose 

1252 ith value is a(b(c(i))). 

1253 

1254 a, b, c, ... can be Permutation objects or tuples. 

1255 

1256 Examples 

1257 ======== 

1258 

1259 >>> from sympy.combinatorics import Permutation 

1260 

1261 >>> a, b = [1, 0, 2], [0, 2, 1] 

1262 >>> a = Permutation(a); b = Permutation(b) 

1263 >>> list(Permutation.rmul(a, b)) 

1264 [1, 2, 0] 

1265 >>> [a(b(i)) for i in range(3)] 

1266 [1, 2, 0] 

1267 

1268 This handles the operands in reverse order compared to the ``*`` operator: 

1269 

1270 >>> a = Permutation(a); b = Permutation(b) 

1271 >>> list(a*b) 

1272 [2, 0, 1] 

1273 >>> [b(a(i)) for i in range(3)] 

1274 [2, 0, 1] 

1275 

1276 Notes 

1277 ===== 

1278 

1279 All items in the sequence will be parsed by Permutation as 

1280 necessary as long as the first item is a Permutation: 

1281 

1282 >>> Permutation.rmul(a, [0, 2, 1]) == Permutation.rmul(a, b) 

1283 True 

1284 

1285 The reverse order of arguments will raise a TypeError. 

1286 

1287 """ 

1288 rv = args[0] 

1289 for i in range(1, len(args)): 

1290 rv = args[i]*rv 

1291 return rv 

1292 

1293 @classmethod 

1294 def rmul_with_af(cls, *args): 

1295 """ 

1296 same as rmul, but the elements of args are Permutation objects 

1297 which have _array_form 

1298 """ 

1299 a = [x._array_form for x in args] 

1300 rv = cls._af_new(_af_rmuln(*a)) 

1301 return rv 

1302 

1303 def mul_inv(self, other): 

1304 """ 

1305 other*~self, self and other have _array_form 

1306 """ 

1307 a = _af_invert(self._array_form) 

1308 b = other._array_form 

1309 return self._af_new(_af_rmul(a, b)) 

1310 

1311 def __rmul__(self, other): 

1312 """This is needed to coerce other to Permutation in rmul.""" 

1313 cls = type(self) 

1314 return cls(other)*self 

1315 

1316 def __mul__(self, other): 

1317 """ 

1318 Return the product a*b as a Permutation; the ith value is b(a(i)). 

1319 

1320 Examples 

1321 ======== 

1322 

1323 >>> from sympy.combinatorics.permutations import _af_rmul, Permutation 

1324 

1325 >>> a, b = [1, 0, 2], [0, 2, 1] 

1326 >>> a = Permutation(a); b = Permutation(b) 

1327 >>> list(a*b) 

1328 [2, 0, 1] 

1329 >>> [b(a(i)) for i in range(3)] 

1330 [2, 0, 1] 

1331 

1332 This handles operands in reverse order compared to _af_rmul and rmul: 

1333 

1334 >>> al = list(a); bl = list(b) 

1335 >>> _af_rmul(al, bl) 

1336 [1, 2, 0] 

1337 >>> [al[bl[i]] for i in range(3)] 

1338 [1, 2, 0] 

1339 

1340 It is acceptable for the arrays to have different lengths; the shorter 

1341 one will be padded to match the longer one: 

1342 

1343 >>> from sympy import init_printing 

1344 >>> init_printing(perm_cyclic=False, pretty_print=False) 

1345 >>> b*Permutation([1, 0]) 

1346 Permutation([1, 2, 0]) 

1347 >>> Permutation([1, 0])*b 

1348 Permutation([2, 0, 1]) 

1349 

1350 It is also acceptable to allow coercion to handle conversion of a 

1351 single list to the left of a Permutation: 

1352 

1353 >>> [0, 1]*a # no change: 2-element identity 

1354 Permutation([1, 0, 2]) 

1355 >>> [[0, 1]]*a # exchange first two elements 

1356 Permutation([0, 1, 2]) 

1357 

1358 You cannot use more than 1 cycle notation in a product of cycles 

1359 since coercion can only handle one argument to the left. To handle 

1360 multiple cycles it is convenient to use Cycle instead of Permutation: 

1361 

1362 >>> [[1, 2]]*[[2, 3]]*Permutation([]) # doctest: +SKIP 

1363 >>> from sympy.combinatorics.permutations import Cycle 

1364 >>> Cycle(1, 2)(2, 3) 

1365 (1 3 2) 

1366 

1367 """ 

1368 from sympy.combinatorics.perm_groups import PermutationGroup, Coset 

1369 if isinstance(other, PermutationGroup): 

1370 return Coset(self, other, dir='-') 

1371 a = self.array_form 

1372 # __rmul__ makes sure the other is a Permutation 

1373 b = other.array_form 

1374 if not b: 

1375 perm = a 

1376 else: 

1377 b.extend(list(range(len(b), len(a)))) 

1378 perm = [b[i] for i in a] + b[len(a):] 

1379 return self._af_new(perm) 

1380 

1381 def commutes_with(self, other): 

1382 """ 

1383 Checks if the elements are commuting. 

1384 

1385 Examples 

1386 ======== 

1387 

1388 >>> from sympy.combinatorics import Permutation 

1389 >>> a = Permutation([1, 4, 3, 0, 2, 5]) 

1390 >>> b = Permutation([0, 1, 2, 3, 4, 5]) 

1391 >>> a.commutes_with(b) 

1392 True 

1393 >>> b = Permutation([2, 3, 5, 4, 1, 0]) 

1394 >>> a.commutes_with(b) 

1395 False 

1396 """ 

1397 a = self.array_form 

1398 b = other.array_form 

1399 return _af_commutes_with(a, b) 

1400 

1401 def __pow__(self, n): 

1402 """ 

1403 Routine for finding powers of a permutation. 

1404 

1405 Examples 

1406 ======== 

1407 

1408 >>> from sympy.combinatorics import Permutation 

1409 >>> from sympy import init_printing 

1410 >>> init_printing(perm_cyclic=False, pretty_print=False) 

1411 >>> p = Permutation([2, 0, 3, 1]) 

1412 >>> p.order() 

1413 4 

1414 >>> p**4 

1415 Permutation([0, 1, 2, 3]) 

1416 """ 

1417 if isinstance(n, Permutation): 

1418 raise NotImplementedError( 

1419 'p**p is not defined; do you mean p^p (conjugate)?') 

1420 n = int(n) 

1421 return self._af_new(_af_pow(self.array_form, n)) 

1422 

1423 def __rxor__(self, i): 

1424 """Return self(i) when ``i`` is an int. 

1425 

1426 Examples 

1427 ======== 

1428 

1429 >>> from sympy.combinatorics import Permutation 

1430 >>> p = Permutation(1, 2, 9) 

1431 >>> 2^p == p(2) == 9 

1432 True 

1433 """ 

1434 if int(i) == i: 

1435 return self(i) 

1436 else: 

1437 raise NotImplementedError( 

1438 "i^p = p(i) when i is an integer, not %s." % i) 

1439 

1440 def __xor__(self, h): 

1441 """Return the conjugate permutation ``~h*self*h` `. 

1442 

1443 Explanation 

1444 =========== 

1445 

1446 If ``a`` and ``b`` are conjugates, ``a = h*b*~h`` and 

1447 ``b = ~h*a*h`` and both have the same cycle structure. 

1448 

1449 Examples 

1450 ======== 

1451 

1452 >>> from sympy.combinatorics import Permutation 

1453 >>> p = Permutation(1, 2, 9) 

1454 >>> q = Permutation(6, 9, 8) 

1455 >>> p*q != q*p 

1456 True 

1457 

1458 Calculate and check properties of the conjugate: 

1459 

1460 >>> c = p^q 

1461 >>> c == ~q*p*q and p == q*c*~q 

1462 True 

1463 

1464 The expression q^p^r is equivalent to q^(p*r): 

1465 

1466 >>> r = Permutation(9)(4, 6, 8) 

1467 >>> q^p^r == q^(p*r) 

1468 True 

1469 

1470 If the term to the left of the conjugate operator, i, is an integer 

1471 then this is interpreted as selecting the ith element from the 

1472 permutation to the right: 

1473 

1474 >>> all(i^p == p(i) for i in range(p.size)) 

1475 True 

1476 

1477 Note that the * operator as higher precedence than the ^ operator: 

1478 

1479 >>> q^r*p^r == q^(r*p)^r == Permutation(9)(1, 6, 4) 

1480 True 

1481 

1482 Notes 

1483 ===== 

1484 

1485 In Python the precedence rule is p^q^r = (p^q)^r which differs 

1486 in general from p^(q^r) 

1487 

1488 >>> q^p^r 

1489 (9)(1 4 8) 

1490 >>> q^(p^r) 

1491 (9)(1 8 6) 

1492 

1493 For a given r and p, both of the following are conjugates of p: 

1494 ~r*p*r and r*p*~r. But these are not necessarily the same: 

1495 

1496 >>> ~r*p*r == r*p*~r 

1497 True 

1498 

1499 >>> p = Permutation(1, 2, 9)(5, 6) 

1500 >>> ~r*p*r == r*p*~r 

1501 False 

1502 

1503 The conjugate ~r*p*r was chosen so that ``p^q^r`` would be equivalent 

1504 to ``p^(q*r)`` rather than ``p^(r*q)``. To obtain r*p*~r, pass ~r to 

1505 this method: 

1506 

1507 >>> p^~r == r*p*~r 

1508 True 

1509 """ 

1510 

1511 if self.size != h.size: 

1512 raise ValueError("The permutations must be of equal size.") 

1513 a = [None]*self.size 

1514 h = h._array_form 

1515 p = self._array_form 

1516 for i in range(self.size): 

1517 a[h[i]] = h[p[i]] 

1518 return self._af_new(a) 

1519 

1520 def transpositions(self): 

1521 """ 

1522 Return the permutation decomposed into a list of transpositions. 

1523 

1524 Explanation 

1525 =========== 

1526 

1527 It is always possible to express a permutation as the product of 

1528 transpositions, see [1] 

1529 

1530 Examples 

1531 ======== 

1532 

1533 >>> from sympy.combinatorics import Permutation 

1534 >>> p = Permutation([[1, 2, 3], [0, 4, 5, 6, 7]]) 

1535 >>> t = p.transpositions() 

1536 >>> t 

1537 [(0, 7), (0, 6), (0, 5), (0, 4), (1, 3), (1, 2)] 

1538 >>> print(''.join(str(c) for c in t)) 

1539 (0, 7)(0, 6)(0, 5)(0, 4)(1, 3)(1, 2) 

1540 >>> Permutation.rmul(*[Permutation([ti], size=p.size) for ti in t]) == p 

1541 True 

1542 

1543 References 

1544 ========== 

1545 

1546 .. [1] https://en.wikipedia.org/wiki/Transposition_%28mathematics%29#Properties 

1547 

1548 """ 

1549 a = self.cyclic_form 

1550 res = [] 

1551 for x in a: 

1552 nx = len(x) 

1553 if nx == 2: 

1554 res.append(tuple(x)) 

1555 elif nx > 2: 

1556 first = x[0] 

1557 for y in x[nx - 1:0:-1]: 

1558 res.append((first, y)) 

1559 return res 

1560 

1561 @classmethod 

1562 def from_sequence(self, i, key=None): 

1563 """Return the permutation needed to obtain ``i`` from the sorted 

1564 elements of ``i``. If custom sorting is desired, a key can be given. 

1565 

1566 Examples 

1567 ======== 

1568 

1569 >>> from sympy.combinatorics import Permutation 

1570 

1571 >>> Permutation.from_sequence('SymPy') 

1572 (4)(0 1 3) 

1573 >>> _(sorted("SymPy")) 

1574 ['S', 'y', 'm', 'P', 'y'] 

1575 >>> Permutation.from_sequence('SymPy', key=lambda x: x.lower()) 

1576 (4)(0 2)(1 3) 

1577 """ 

1578 ic = list(zip(i, list(range(len(i))))) 

1579 if key: 

1580 ic.sort(key=lambda x: key(x[0])) 

1581 else: 

1582 ic.sort() 

1583 return ~Permutation([i[1] for i in ic]) 

1584 

1585 def __invert__(self): 

1586 """ 

1587 Return the inverse of the permutation. 

1588 

1589 A permutation multiplied by its inverse is the identity permutation. 

1590 

1591 Examples 

1592 ======== 

1593 

1594 >>> from sympy.combinatorics import Permutation 

1595 >>> from sympy import init_printing 

1596 >>> init_printing(perm_cyclic=False, pretty_print=False) 

1597 >>> p = Permutation([[2, 0], [3, 1]]) 

1598 >>> ~p 

1599 Permutation([2, 3, 0, 1]) 

1600 >>> _ == p**-1 

1601 True 

1602 >>> p*~p == ~p*p == Permutation([0, 1, 2, 3]) 

1603 True 

1604 """ 

1605 return self._af_new(_af_invert(self._array_form)) 

1606 

1607 def __iter__(self): 

1608 """Yield elements from array form. 

1609 

1610 Examples 

1611 ======== 

1612 

1613 >>> from sympy.combinatorics import Permutation 

1614 >>> list(Permutation(range(3))) 

1615 [0, 1, 2] 

1616 """ 

1617 yield from self.array_form 

1618 

1619 def __repr__(self): 

1620 return srepr(self) 

1621 

1622 def __call__(self, *i): 

1623 """ 

1624 Allows applying a permutation instance as a bijective function. 

1625 

1626 Examples 

1627 ======== 

1628 

1629 >>> from sympy.combinatorics import Permutation 

1630 >>> p = Permutation([[2, 0], [3, 1]]) 

1631 >>> p.array_form 

1632 [2, 3, 0, 1] 

1633 >>> [p(i) for i in range(4)] 

1634 [2, 3, 0, 1] 

1635 

1636 If an array is given then the permutation selects the items 

1637 from the array (i.e. the permutation is applied to the array): 

1638 

1639 >>> from sympy.abc import x 

1640 >>> p([x, 1, 0, x**2]) 

1641 [0, x**2, x, 1] 

1642 """ 

1643 # list indices can be Integer or int; leave this 

1644 # as it is (don't test or convert it) because this 

1645 # gets called a lot and should be fast 

1646 if len(i) == 1: 

1647 i = i[0] 

1648 if not isinstance(i, Iterable): 

1649 i = as_int(i) 

1650 if i < 0 or i > self.size: 

1651 raise TypeError( 

1652 "{} should be an integer between 0 and {}" 

1653 .format(i, self.size-1)) 

1654 return self._array_form[i] 

1655 # P([a, b, c]) 

1656 if len(i) != self.size: 

1657 raise TypeError( 

1658 "{} should have the length {}.".format(i, self.size)) 

1659 return [i[j] for j in self._array_form] 

1660 # P(1, 2, 3) 

1661 return self*Permutation(Cycle(*i), size=self.size) 

1662 

1663 def atoms(self): 

1664 """ 

1665 Returns all the elements of a permutation 

1666 

1667 Examples 

1668 ======== 

1669 

1670 >>> from sympy.combinatorics import Permutation 

1671 >>> Permutation([0, 1, 2, 3, 4, 5]).atoms() 

1672 {0, 1, 2, 3, 4, 5} 

1673 >>> Permutation([[0, 1], [2, 3], [4, 5]]).atoms() 

1674 {0, 1, 2, 3, 4, 5} 

1675 """ 

1676 return set(self.array_form) 

1677 

1678 def apply(self, i): 

1679 r"""Apply the permutation to an expression. 

1680 

1681 Parameters 

1682 ========== 

1683 

1684 i : Expr 

1685 It should be an integer between $0$ and $n-1$ where $n$ 

1686 is the size of the permutation. 

1687 

1688 If it is a symbol or a symbolic expression that can 

1689 have integer values, an ``AppliedPermutation`` object 

1690 will be returned which can represent an unevaluated 

1691 function. 

1692 

1693 Notes 

1694 ===== 

1695 

1696 Any permutation can be defined as a bijective function 

1697 $\sigma : \{ 0, 1, \dots, n-1 \} \rightarrow \{ 0, 1, \dots, n-1 \}$ 

1698 where $n$ denotes the size of the permutation. 

1699 

1700 The definition may even be extended for any set with distinctive 

1701 elements, such that the permutation can even be applied for 

1702 real numbers or such, however, it is not implemented for now for 

1703 computational reasons and the integrity with the group theory 

1704 module. 

1705 

1706 This function is similar to the ``__call__`` magic, however, 

1707 ``__call__`` magic already has some other applications like 

1708 permuting an array or attaching new cycles, which would 

1709 not always be mathematically consistent. 

1710 

1711 This also guarantees that the return type is a SymPy integer, 

1712 which guarantees the safety to use assumptions. 

1713 """ 

1714 i = _sympify(i) 

1715 if i.is_integer is False: 

1716 raise NotImplementedError("{} should be an integer.".format(i)) 

1717 

1718 n = self.size 

1719 if (i < 0) == True or (i >= n) == True: 

1720 raise NotImplementedError( 

1721 "{} should be an integer between 0 and {}".format(i, n-1)) 

1722 

1723 if i.is_Integer: 

1724 return Integer(self._array_form[i]) 

1725 return AppliedPermutation(self, i) 

1726 

1727 def next_lex(self): 

1728 """ 

1729 Returns the next permutation in lexicographical order. 

1730 If self is the last permutation in lexicographical order 

1731 it returns None. 

1732 See [4] section 2.4. 

1733 

1734 

1735 Examples 

1736 ======== 

1737 

1738 >>> from sympy.combinatorics import Permutation 

1739 >>> p = Permutation([2, 3, 1, 0]) 

1740 >>> p = Permutation([2, 3, 1, 0]); p.rank() 

1741 17 

1742 >>> p = p.next_lex(); p.rank() 

1743 18 

1744 

1745 See Also 

1746 ======== 

1747 

1748 rank, unrank_lex 

1749 """ 

1750 perm = self.array_form[:] 

1751 n = len(perm) 

1752 i = n - 2 

1753 while perm[i + 1] < perm[i]: 

1754 i -= 1 

1755 if i == -1: 

1756 return None 

1757 else: 

1758 j = n - 1 

1759 while perm[j] < perm[i]: 

1760 j -= 1 

1761 perm[j], perm[i] = perm[i], perm[j] 

1762 i += 1 

1763 j = n - 1 

1764 while i < j: 

1765 perm[j], perm[i] = perm[i], perm[j] 

1766 i += 1 

1767 j -= 1 

1768 return self._af_new(perm) 

1769 

1770 @classmethod 

1771 def unrank_nonlex(self, n, r): 

1772 """ 

1773 This is a linear time unranking algorithm that does not 

1774 respect lexicographic order [3]. 

1775 

1776 Examples 

1777 ======== 

1778 

1779 >>> from sympy.combinatorics import Permutation 

1780 >>> from sympy import init_printing 

1781 >>> init_printing(perm_cyclic=False, pretty_print=False) 

1782 >>> Permutation.unrank_nonlex(4, 5) 

1783 Permutation([2, 0, 3, 1]) 

1784 >>> Permutation.unrank_nonlex(4, -1) 

1785 Permutation([0, 1, 2, 3]) 

1786 

1787 See Also 

1788 ======== 

1789 

1790 next_nonlex, rank_nonlex 

1791 """ 

1792 def _unrank1(n, r, a): 

1793 if n > 0: 

1794 a[n - 1], a[r % n] = a[r % n], a[n - 1] 

1795 _unrank1(n - 1, r//n, a) 

1796 

1797 id_perm = list(range(n)) 

1798 n = int(n) 

1799 r = r % ifac(n) 

1800 _unrank1(n, r, id_perm) 

1801 return self._af_new(id_perm) 

1802 

1803 def rank_nonlex(self, inv_perm=None): 

1804 """ 

1805 This is a linear time ranking algorithm that does not 

1806 enforce lexicographic order [3]. 

1807 

1808 

1809 Examples 

1810 ======== 

1811 

1812 >>> from sympy.combinatorics import Permutation 

1813 >>> p = Permutation([0, 1, 2, 3]) 

1814 >>> p.rank_nonlex() 

1815 23 

1816 

1817 See Also 

1818 ======== 

1819 

1820 next_nonlex, unrank_nonlex 

1821 """ 

1822 def _rank1(n, perm, inv_perm): 

1823 if n == 1: 

1824 return 0 

1825 s = perm[n - 1] 

1826 t = inv_perm[n - 1] 

1827 perm[n - 1], perm[t] = perm[t], s 

1828 inv_perm[n - 1], inv_perm[s] = inv_perm[s], t 

1829 return s + n*_rank1(n - 1, perm, inv_perm) 

1830 

1831 if inv_perm is None: 

1832 inv_perm = (~self).array_form 

1833 if not inv_perm: 

1834 return 0 

1835 perm = self.array_form[:] 

1836 r = _rank1(len(perm), perm, inv_perm) 

1837 return r 

1838 

1839 def next_nonlex(self): 

1840 """ 

1841 Returns the next permutation in nonlex order [3]. 

1842 If self is the last permutation in this order it returns None. 

1843 

1844 Examples 

1845 ======== 

1846 

1847 >>> from sympy.combinatorics import Permutation 

1848 >>> from sympy import init_printing 

1849 >>> init_printing(perm_cyclic=False, pretty_print=False) 

1850 >>> p = Permutation([2, 0, 3, 1]); p.rank_nonlex() 

1851 5 

1852 >>> p = p.next_nonlex(); p 

1853 Permutation([3, 0, 1, 2]) 

1854 >>> p.rank_nonlex() 

1855 6 

1856 

1857 See Also 

1858 ======== 

1859 

1860 rank_nonlex, unrank_nonlex 

1861 """ 

1862 r = self.rank_nonlex() 

1863 if r == ifac(self.size) - 1: 

1864 return None 

1865 return self.unrank_nonlex(self.size, r + 1) 

1866 

1867 def rank(self): 

1868 """ 

1869 Returns the lexicographic rank of the permutation. 

1870 

1871 Examples 

1872 ======== 

1873 

1874 >>> from sympy.combinatorics import Permutation 

1875 >>> p = Permutation([0, 1, 2, 3]) 

1876 >>> p.rank() 

1877 0 

1878 >>> p = Permutation([3, 2, 1, 0]) 

1879 >>> p.rank() 

1880 23 

1881 

1882 See Also 

1883 ======== 

1884 

1885 next_lex, unrank_lex, cardinality, length, order, size 

1886 """ 

1887 if self._rank is not None: 

1888 return self._rank 

1889 rank = 0 

1890 rho = self.array_form[:] 

1891 n = self.size - 1 

1892 size = n + 1 

1893 psize = int(ifac(n)) 

1894 for j in range(size - 1): 

1895 rank += rho[j]*psize 

1896 for i in range(j + 1, size): 

1897 if rho[i] > rho[j]: 

1898 rho[i] -= 1 

1899 psize //= n 

1900 n -= 1 

1901 self._rank = rank 

1902 return rank 

1903 

1904 @property 

1905 def cardinality(self): 

1906 """ 

1907 Returns the number of all possible permutations. 

1908 

1909 Examples 

1910 ======== 

1911 

1912 >>> from sympy.combinatorics import Permutation 

1913 >>> p = Permutation([0, 1, 2, 3]) 

1914 >>> p.cardinality 

1915 24 

1916 

1917 See Also 

1918 ======== 

1919 

1920 length, order, rank, size 

1921 """ 

1922 return int(ifac(self.size)) 

1923 

1924 def parity(self): 

1925 """ 

1926 Computes the parity of a permutation. 

1927 

1928 Explanation 

1929 =========== 

1930 

1931 The parity of a permutation reflects the parity of the 

1932 number of inversions in the permutation, i.e., the 

1933 number of pairs of x and y such that ``x > y`` but ``p[x] < p[y]``. 

1934 

1935 Examples 

1936 ======== 

1937 

1938 >>> from sympy.combinatorics import Permutation 

1939 >>> p = Permutation([0, 1, 2, 3]) 

1940 >>> p.parity() 

1941 0 

1942 >>> p = Permutation([3, 2, 0, 1]) 

1943 >>> p.parity() 

1944 1 

1945 

1946 See Also 

1947 ======== 

1948 

1949 _af_parity 

1950 """ 

1951 if self._cyclic_form is not None: 

1952 return (self.size - self.cycles) % 2 

1953 

1954 return _af_parity(self.array_form) 

1955 

1956 @property 

1957 def is_even(self): 

1958 """ 

1959 Checks if a permutation is even. 

1960 

1961 Examples 

1962 ======== 

1963 

1964 >>> from sympy.combinatorics import Permutation 

1965 >>> p = Permutation([0, 1, 2, 3]) 

1966 >>> p.is_even 

1967 True 

1968 >>> p = Permutation([3, 2, 1, 0]) 

1969 >>> p.is_even 

1970 True 

1971 

1972 See Also 

1973 ======== 

1974 

1975 is_odd 

1976 """ 

1977 return not self.is_odd 

1978 

1979 @property 

1980 def is_odd(self): 

1981 """ 

1982 Checks if a permutation is odd. 

1983 

1984 Examples 

1985 ======== 

1986 

1987 >>> from sympy.combinatorics import Permutation 

1988 >>> p = Permutation([0, 1, 2, 3]) 

1989 >>> p.is_odd 

1990 False 

1991 >>> p = Permutation([3, 2, 0, 1]) 

1992 >>> p.is_odd 

1993 True 

1994 

1995 See Also 

1996 ======== 

1997 

1998 is_even 

1999 """ 

2000 return bool(self.parity() % 2) 

2001 

2002 @property 

2003 def is_Singleton(self): 

2004 """ 

2005 Checks to see if the permutation contains only one number and is 

2006 thus the only possible permutation of this set of numbers 

2007 

2008 Examples 

2009 ======== 

2010 

2011 >>> from sympy.combinatorics import Permutation 

2012 >>> Permutation([0]).is_Singleton 

2013 True 

2014 >>> Permutation([0, 1]).is_Singleton 

2015 False 

2016 

2017 See Also 

2018 ======== 

2019 

2020 is_Empty 

2021 """ 

2022 return self.size == 1 

2023 

2024 @property 

2025 def is_Empty(self): 

2026 """ 

2027 Checks to see if the permutation is a set with zero elements 

2028 

2029 Examples 

2030 ======== 

2031 

2032 >>> from sympy.combinatorics import Permutation 

2033 >>> Permutation([]).is_Empty 

2034 True 

2035 >>> Permutation([0]).is_Empty 

2036 False 

2037 

2038 See Also 

2039 ======== 

2040 

2041 is_Singleton 

2042 """ 

2043 return self.size == 0 

2044 

2045 @property 

2046 def is_identity(self): 

2047 return self.is_Identity 

2048 

2049 @property 

2050 def is_Identity(self): 

2051 """ 

2052 Returns True if the Permutation is an identity permutation. 

2053 

2054 Examples 

2055 ======== 

2056 

2057 >>> from sympy.combinatorics import Permutation 

2058 >>> p = Permutation([]) 

2059 >>> p.is_Identity 

2060 True 

2061 >>> p = Permutation([[0], [1], [2]]) 

2062 >>> p.is_Identity 

2063 True 

2064 >>> p = Permutation([0, 1, 2]) 

2065 >>> p.is_Identity 

2066 True 

2067 >>> p = Permutation([0, 2, 1]) 

2068 >>> p.is_Identity 

2069 False 

2070 

2071 See Also 

2072 ======== 

2073 

2074 order 

2075 """ 

2076 af = self.array_form 

2077 return not af or all(i == af[i] for i in range(self.size)) 

2078 

2079 def ascents(self): 

2080 """ 

2081 Returns the positions of ascents in a permutation, ie, the location 

2082 where p[i] < p[i+1] 

2083 

2084 Examples 

2085 ======== 

2086 

2087 >>> from sympy.combinatorics import Permutation 

2088 >>> p = Permutation([4, 0, 1, 3, 2]) 

2089 >>> p.ascents() 

2090 [1, 2] 

2091 

2092 See Also 

2093 ======== 

2094 

2095 descents, inversions, min, max 

2096 """ 

2097 a = self.array_form 

2098 pos = [i for i in range(len(a) - 1) if a[i] < a[i + 1]] 

2099 return pos 

2100 

2101 def descents(self): 

2102 """ 

2103 Returns the positions of descents in a permutation, ie, the location 

2104 where p[i] > p[i+1] 

2105 

2106 Examples 

2107 ======== 

2108 

2109 >>> from sympy.combinatorics import Permutation 

2110 >>> p = Permutation([4, 0, 1, 3, 2]) 

2111 >>> p.descents() 

2112 [0, 3] 

2113 

2114 See Also 

2115 ======== 

2116 

2117 ascents, inversions, min, max 

2118 """ 

2119 a = self.array_form 

2120 pos = [i for i in range(len(a) - 1) if a[i] > a[i + 1]] 

2121 return pos 

2122 

2123 def max(self): 

2124 """ 

2125 The maximum element moved by the permutation. 

2126 

2127 Examples 

2128 ======== 

2129 

2130 >>> from sympy.combinatorics import Permutation 

2131 >>> p = Permutation([1, 0, 2, 3, 4]) 

2132 >>> p.max() 

2133 1 

2134 

2135 See Also 

2136 ======== 

2137 

2138 min, descents, ascents, inversions 

2139 """ 

2140 max = 0 

2141 a = self.array_form 

2142 for i in range(len(a)): 

2143 if a[i] != i and a[i] > max: 

2144 max = a[i] 

2145 return max 

2146 

2147 def min(self): 

2148 """ 

2149 The minimum element moved by the permutation. 

2150 

2151 Examples 

2152 ======== 

2153 

2154 >>> from sympy.combinatorics import Permutation 

2155 >>> p = Permutation([0, 1, 4, 3, 2]) 

2156 >>> p.min() 

2157 2 

2158 

2159 See Also 

2160 ======== 

2161 

2162 max, descents, ascents, inversions 

2163 """ 

2164 a = self.array_form 

2165 min = len(a) 

2166 for i in range(len(a)): 

2167 if a[i] != i and a[i] < min: 

2168 min = a[i] 

2169 return min 

2170 

2171 def inversions(self): 

2172 """ 

2173 Computes the number of inversions of a permutation. 

2174 

2175 Explanation 

2176 =========== 

2177 

2178 An inversion is where i > j but p[i] < p[j]. 

2179 

2180 For small length of p, it iterates over all i and j 

2181 values and calculates the number of inversions. 

2182 For large length of p, it uses a variation of merge 

2183 sort to calculate the number of inversions. 

2184 

2185 Examples 

2186 ======== 

2187 

2188 >>> from sympy.combinatorics import Permutation 

2189 >>> p = Permutation([0, 1, 2, 3, 4, 5]) 

2190 >>> p.inversions() 

2191 0 

2192 >>> Permutation([3, 2, 1, 0]).inversions() 

2193 6 

2194 

2195 See Also 

2196 ======== 

2197 

2198 descents, ascents, min, max 

2199 

2200 References 

2201 ========== 

2202 

2203 .. [1] https://www.cp.eng.chula.ac.th/~prabhas//teaching/algo/algo2008/count-inv.htm 

2204 

2205 """ 

2206 inversions = 0 

2207 a = self.array_form 

2208 n = len(a) 

2209 if n < 130: 

2210 for i in range(n - 1): 

2211 b = a[i] 

2212 for c in a[i + 1:]: 

2213 if b > c: 

2214 inversions += 1 

2215 else: 

2216 k = 1 

2217 right = 0 

2218 arr = a[:] 

2219 temp = a[:] 

2220 while k < n: 

2221 i = 0 

2222 while i + k < n: 

2223 right = i + k * 2 - 1 

2224 if right >= n: 

2225 right = n - 1 

2226 inversions += _merge(arr, temp, i, i + k, right) 

2227 i = i + k * 2 

2228 k = k * 2 

2229 return inversions 

2230 

2231 def commutator(self, x): 

2232 """Return the commutator of ``self`` and ``x``: ``~x*~self*x*self`` 

2233 

2234 If f and g are part of a group, G, then the commutator of f and g 

2235 is the group identity iff f and g commute, i.e. fg == gf. 

2236 

2237 Examples 

2238 ======== 

2239 

2240 >>> from sympy.combinatorics import Permutation 

2241 >>> from sympy import init_printing 

2242 >>> init_printing(perm_cyclic=False, pretty_print=False) 

2243 >>> p = Permutation([0, 2, 3, 1]) 

2244 >>> x = Permutation([2, 0, 3, 1]) 

2245 >>> c = p.commutator(x); c 

2246 Permutation([2, 1, 3, 0]) 

2247 >>> c == ~x*~p*x*p 

2248 True 

2249 

2250 >>> I = Permutation(3) 

2251 >>> p = [I + i for i in range(6)] 

2252 >>> for i in range(len(p)): 

2253 ... for j in range(len(p)): 

2254 ... c = p[i].commutator(p[j]) 

2255 ... if p[i]*p[j] == p[j]*p[i]: 

2256 ... assert c == I 

2257 ... else: 

2258 ... assert c != I 

2259 ... 

2260 

2261 References 

2262 ========== 

2263 

2264 .. [1] https://en.wikipedia.org/wiki/Commutator 

2265 """ 

2266 

2267 a = self.array_form 

2268 b = x.array_form 

2269 n = len(a) 

2270 if len(b) != n: 

2271 raise ValueError("The permutations must be of equal size.") 

2272 inva = [None]*n 

2273 for i in range(n): 

2274 inva[a[i]] = i 

2275 invb = [None]*n 

2276 for i in range(n): 

2277 invb[b[i]] = i 

2278 return self._af_new([a[b[inva[i]]] for i in invb]) 

2279 

2280 def signature(self): 

2281 """ 

2282 Gives the signature of the permutation needed to place the 

2283 elements of the permutation in canonical order. 

2284 

2285 The signature is calculated as (-1)^<number of inversions> 

2286 

2287 Examples 

2288 ======== 

2289 

2290 >>> from sympy.combinatorics import Permutation 

2291 >>> p = Permutation([0, 1, 2]) 

2292 >>> p.inversions() 

2293 0 

2294 >>> p.signature() 

2295 1 

2296 >>> q = Permutation([0,2,1]) 

2297 >>> q.inversions() 

2298 1 

2299 >>> q.signature() 

2300 -1 

2301 

2302 See Also 

2303 ======== 

2304 

2305 inversions 

2306 """ 

2307 if self.is_even: 

2308 return 1 

2309 return -1 

2310 

2311 def order(self): 

2312 """ 

2313 Computes the order of a permutation. 

2314 

2315 When the permutation is raised to the power of its 

2316 order it equals the identity permutation. 

2317 

2318 Examples 

2319 ======== 

2320 

2321 >>> from sympy.combinatorics import Permutation 

2322 >>> from sympy import init_printing 

2323 >>> init_printing(perm_cyclic=False, pretty_print=False) 

2324 >>> p = Permutation([3, 1, 5, 2, 4, 0]) 

2325 >>> p.order() 

2326 4 

2327 >>> (p**(p.order())) 

2328 Permutation([], size=6) 

2329 

2330 See Also 

2331 ======== 

2332 

2333 identity, cardinality, length, rank, size 

2334 """ 

2335 

2336 return reduce(lcm, [len(cycle) for cycle in self.cyclic_form], 1) 

2337 

2338 def length(self): 

2339 """ 

2340 Returns the number of integers moved by a permutation. 

2341 

2342 Examples 

2343 ======== 

2344 

2345 >>> from sympy.combinatorics import Permutation 

2346 >>> Permutation([0, 3, 2, 1]).length() 

2347 2 

2348 >>> Permutation([[0, 1], [2, 3]]).length() 

2349 4 

2350 

2351 See Also 

2352 ======== 

2353 

2354 min, max, support, cardinality, order, rank, size 

2355 """ 

2356 

2357 return len(self.support()) 

2358 

2359 @property 

2360 def cycle_structure(self): 

2361 """Return the cycle structure of the permutation as a dictionary 

2362 indicating the multiplicity of each cycle length. 

2363 

2364 Examples 

2365 ======== 

2366 

2367 >>> from sympy.combinatorics import Permutation 

2368 >>> Permutation(3).cycle_structure 

2369 {1: 4} 

2370 >>> Permutation(0, 4, 3)(1, 2)(5, 6).cycle_structure 

2371 {2: 2, 3: 1} 

2372 """ 

2373 if self._cycle_structure: 

2374 rv = self._cycle_structure 

2375 else: 

2376 rv = defaultdict(int) 

2377 singletons = self.size 

2378 for c in self.cyclic_form: 

2379 rv[len(c)] += 1 

2380 singletons -= len(c) 

2381 if singletons: 

2382 rv[1] = singletons 

2383 self._cycle_structure = rv 

2384 return dict(rv) # make a copy 

2385 

2386 @property 

2387 def cycles(self): 

2388 """ 

2389 Returns the number of cycles contained in the permutation 

2390 (including singletons). 

2391 

2392 Examples 

2393 ======== 

2394 

2395 >>> from sympy.combinatorics import Permutation 

2396 >>> Permutation([0, 1, 2]).cycles 

2397 3 

2398 >>> Permutation([0, 1, 2]).full_cyclic_form 

2399 [[0], [1], [2]] 

2400 >>> Permutation(0, 1)(2, 3).cycles 

2401 2 

2402 

2403 See Also 

2404 ======== 

2405 sympy.functions.combinatorial.numbers.stirling 

2406 """ 

2407 return len(self.full_cyclic_form) 

2408 

2409 def index(self): 

2410 """ 

2411 Returns the index of a permutation. 

2412 

2413 The index of a permutation is the sum of all subscripts j such 

2414 that p[j] is greater than p[j+1]. 

2415 

2416 Examples 

2417 ======== 

2418 

2419 >>> from sympy.combinatorics import Permutation 

2420 >>> p = Permutation([3, 0, 2, 1, 4]) 

2421 >>> p.index() 

2422 2 

2423 """ 

2424 a = self.array_form 

2425 

2426 return sum([j for j in range(len(a) - 1) if a[j] > a[j + 1]]) 

2427 

2428 def runs(self): 

2429 """ 

2430 Returns the runs of a permutation. 

2431 

2432 An ascending sequence in a permutation is called a run [5]. 

2433 

2434 

2435 Examples 

2436 ======== 

2437 

2438 >>> from sympy.combinatorics import Permutation 

2439 >>> p = Permutation([2, 5, 7, 3, 6, 0, 1, 4, 8]) 

2440 >>> p.runs() 

2441 [[2, 5, 7], [3, 6], [0, 1, 4, 8]] 

2442 >>> q = Permutation([1,3,2,0]) 

2443 >>> q.runs() 

2444 [[1, 3], [2], [0]] 

2445 """ 

2446 return runs(self.array_form) 

2447 

2448 def inversion_vector(self): 

2449 """Return the inversion vector of the permutation. 

2450 

2451 The inversion vector consists of elements whose value 

2452 indicates the number of elements in the permutation 

2453 that are lesser than it and lie on its right hand side. 

2454 

2455 The inversion vector is the same as the Lehmer encoding of a 

2456 permutation. 

2457 

2458 Examples 

2459 ======== 

2460 

2461 >>> from sympy.combinatorics import Permutation 

2462 >>> p = Permutation([4, 8, 0, 7, 1, 5, 3, 6, 2]) 

2463 >>> p.inversion_vector() 

2464 [4, 7, 0, 5, 0, 2, 1, 1] 

2465 >>> p = Permutation([3, 2, 1, 0]) 

2466 >>> p.inversion_vector() 

2467 [3, 2, 1] 

2468 

2469 The inversion vector increases lexicographically with the rank 

2470 of the permutation, the -ith element cycling through 0..i. 

2471 

2472 >>> p = Permutation(2) 

2473 >>> while p: 

2474 ... print('%s %s %s' % (p, p.inversion_vector(), p.rank())) 

2475 ... p = p.next_lex() 

2476 (2) [0, 0] 0 

2477 (1 2) [0, 1] 1 

2478 (2)(0 1) [1, 0] 2 

2479 (0 1 2) [1, 1] 3 

2480 (0 2 1) [2, 0] 4 

2481 (0 2) [2, 1] 5 

2482 

2483 See Also 

2484 ======== 

2485 

2486 from_inversion_vector 

2487 """ 

2488 self_array_form = self.array_form 

2489 n = len(self_array_form) 

2490 inversion_vector = [0] * (n - 1) 

2491 

2492 for i in range(n - 1): 

2493 val = 0 

2494 for j in range(i + 1, n): 

2495 if self_array_form[j] < self_array_form[i]: 

2496 val += 1 

2497 inversion_vector[i] = val 

2498 return inversion_vector 

2499 

2500 def rank_trotterjohnson(self): 

2501 """ 

2502 Returns the Trotter Johnson rank, which we get from the minimal 

2503 change algorithm. See [4] section 2.4. 

2504 

2505 Examples 

2506 ======== 

2507 

2508 >>> from sympy.combinatorics import Permutation 

2509 >>> p = Permutation([0, 1, 2, 3]) 

2510 >>> p.rank_trotterjohnson() 

2511 0 

2512 >>> p = Permutation([0, 2, 1, 3]) 

2513 >>> p.rank_trotterjohnson() 

2514 7 

2515 

2516 See Also 

2517 ======== 

2518 

2519 unrank_trotterjohnson, next_trotterjohnson 

2520 """ 

2521 if self.array_form == [] or self.is_Identity: 

2522 return 0 

2523 if self.array_form == [1, 0]: 

2524 return 1 

2525 perm = self.array_form 

2526 n = self.size 

2527 rank = 0 

2528 for j in range(1, n): 

2529 k = 1 

2530 i = 0 

2531 while perm[i] != j: 

2532 if perm[i] < j: 

2533 k += 1 

2534 i += 1 

2535 j1 = j + 1 

2536 if rank % 2 == 0: 

2537 rank = j1*rank + j1 - k 

2538 else: 

2539 rank = j1*rank + k - 1 

2540 return rank 

2541 

2542 @classmethod 

2543 def unrank_trotterjohnson(cls, size, rank): 

2544 """ 

2545 Trotter Johnson permutation unranking. See [4] section 2.4. 

2546 

2547 Examples 

2548 ======== 

2549 

2550 >>> from sympy.combinatorics import Permutation 

2551 >>> from sympy import init_printing 

2552 >>> init_printing(perm_cyclic=False, pretty_print=False) 

2553 >>> Permutation.unrank_trotterjohnson(5, 10) 

2554 Permutation([0, 3, 1, 2, 4]) 

2555 

2556 See Also 

2557 ======== 

2558 

2559 rank_trotterjohnson, next_trotterjohnson 

2560 """ 

2561 perm = [0]*size 

2562 r2 = 0 

2563 n = ifac(size) 

2564 pj = 1 

2565 for j in range(2, size + 1): 

2566 pj *= j 

2567 r1 = (rank * pj) // n 

2568 k = r1 - j*r2 

2569 if r2 % 2 == 0: 

2570 for i in range(j - 1, j - k - 1, -1): 

2571 perm[i] = perm[i - 1] 

2572 perm[j - k - 1] = j - 1 

2573 else: 

2574 for i in range(j - 1, k, -1): 

2575 perm[i] = perm[i - 1] 

2576 perm[k] = j - 1 

2577 r2 = r1 

2578 return cls._af_new(perm) 

2579 

2580 def next_trotterjohnson(self): 

2581 """ 

2582 Returns the next permutation in Trotter-Johnson order. 

2583 If self is the last permutation it returns None. 

2584 See [4] section 2.4. If it is desired to generate all such 

2585 permutations, they can be generated in order more quickly 

2586 with the ``generate_bell`` function. 

2587 

2588 Examples 

2589 ======== 

2590 

2591 >>> from sympy.combinatorics import Permutation 

2592 >>> from sympy import init_printing 

2593 >>> init_printing(perm_cyclic=False, pretty_print=False) 

2594 >>> p = Permutation([3, 0, 2, 1]) 

2595 >>> p.rank_trotterjohnson() 

2596 4 

2597 >>> p = p.next_trotterjohnson(); p 

2598 Permutation([0, 3, 2, 1]) 

2599 >>> p.rank_trotterjohnson() 

2600 5 

2601 

2602 See Also 

2603 ======== 

2604 

2605 rank_trotterjohnson, unrank_trotterjohnson, sympy.utilities.iterables.generate_bell 

2606 """ 

2607 pi = self.array_form[:] 

2608 n = len(pi) 

2609 st = 0 

2610 rho = pi[:] 

2611 done = False 

2612 m = n-1 

2613 while m > 0 and not done: 

2614 d = rho.index(m) 

2615 for i in range(d, m): 

2616 rho[i] = rho[i + 1] 

2617 par = _af_parity(rho[:m]) 

2618 if par == 1: 

2619 if d == m: 

2620 m -= 1 

2621 else: 

2622 pi[st + d], pi[st + d + 1] = pi[st + d + 1], pi[st + d] 

2623 done = True 

2624 else: 

2625 if d == 0: 

2626 m -= 1 

2627 st += 1 

2628 else: 

2629 pi[st + d], pi[st + d - 1] = pi[st + d - 1], pi[st + d] 

2630 done = True 

2631 if m == 0: 

2632 return None 

2633 return self._af_new(pi) 

2634 

2635 def get_precedence_matrix(self): 

2636 """ 

2637 Gets the precedence matrix. This is used for computing the 

2638 distance between two permutations. 

2639 

2640 Examples 

2641 ======== 

2642 

2643 >>> from sympy.combinatorics import Permutation 

2644 >>> from sympy import init_printing 

2645 >>> init_printing(perm_cyclic=False, pretty_print=False) 

2646 >>> p = Permutation.josephus(3, 6, 1) 

2647 >>> p 

2648 Permutation([2, 5, 3, 1, 4, 0]) 

2649 >>> p.get_precedence_matrix() 

2650 Matrix([ 

2651 [0, 0, 0, 0, 0, 0], 

2652 [1, 0, 0, 0, 1, 0], 

2653 [1, 1, 0, 1, 1, 1], 

2654 [1, 1, 0, 0, 1, 0], 

2655 [1, 0, 0, 0, 0, 0], 

2656 [1, 1, 0, 1, 1, 0]]) 

2657 

2658 See Also 

2659 ======== 

2660 

2661 get_precedence_distance, get_adjacency_matrix, get_adjacency_distance 

2662 """ 

2663 m = zeros(self.size) 

2664 perm = self.array_form 

2665 for i in range(m.rows): 

2666 for j in range(i + 1, m.cols): 

2667 m[perm[i], perm[j]] = 1 

2668 return m 

2669 

2670 def get_precedence_distance(self, other): 

2671 """ 

2672 Computes the precedence distance between two permutations. 

2673 

2674 Explanation 

2675 =========== 

2676 

2677 Suppose p and p' represent n jobs. The precedence metric 

2678 counts the number of times a job j is preceded by job i 

2679 in both p and p'. This metric is commutative. 

2680 

2681 Examples 

2682 ======== 

2683 

2684 >>> from sympy.combinatorics import Permutation 

2685 >>> p = Permutation([2, 0, 4, 3, 1]) 

2686 >>> q = Permutation([3, 1, 2, 4, 0]) 

2687 >>> p.get_precedence_distance(q) 

2688 7 

2689 >>> q.get_precedence_distance(p) 

2690 7 

2691 

2692 See Also 

2693 ======== 

2694 

2695 get_precedence_matrix, get_adjacency_matrix, get_adjacency_distance 

2696 """ 

2697 if self.size != other.size: 

2698 raise ValueError("The permutations must be of equal size.") 

2699 self_prec_mat = self.get_precedence_matrix() 

2700 other_prec_mat = other.get_precedence_matrix() 

2701 n_prec = 0 

2702 for i in range(self.size): 

2703 for j in range(self.size): 

2704 if i == j: 

2705 continue 

2706 if self_prec_mat[i, j] * other_prec_mat[i, j] == 1: 

2707 n_prec += 1 

2708 d = self.size * (self.size - 1)//2 - n_prec 

2709 return d 

2710 

2711 def get_adjacency_matrix(self): 

2712 """ 

2713 Computes the adjacency matrix of a permutation. 

2714 

2715 Explanation 

2716 =========== 

2717 

2718 If job i is adjacent to job j in a permutation p 

2719 then we set m[i, j] = 1 where m is the adjacency 

2720 matrix of p. 

2721 

2722 Examples 

2723 ======== 

2724 

2725 >>> from sympy.combinatorics import Permutation 

2726 >>> p = Permutation.josephus(3, 6, 1) 

2727 >>> p.get_adjacency_matrix() 

2728 Matrix([ 

2729 [0, 0, 0, 0, 0, 0], 

2730 [0, 0, 0, 0, 1, 0], 

2731 [0, 0, 0, 0, 0, 1], 

2732 [0, 1, 0, 0, 0, 0], 

2733 [1, 0, 0, 0, 0, 0], 

2734 [0, 0, 0, 1, 0, 0]]) 

2735 >>> q = Permutation([0, 1, 2, 3]) 

2736 >>> q.get_adjacency_matrix() 

2737 Matrix([ 

2738 [0, 1, 0, 0], 

2739 [0, 0, 1, 0], 

2740 [0, 0, 0, 1], 

2741 [0, 0, 0, 0]]) 

2742 

2743 See Also 

2744 ======== 

2745 

2746 get_precedence_matrix, get_precedence_distance, get_adjacency_distance 

2747 """ 

2748 m = zeros(self.size) 

2749 perm = self.array_form 

2750 for i in range(self.size - 1): 

2751 m[perm[i], perm[i + 1]] = 1 

2752 return m 

2753 

2754 def get_adjacency_distance(self, other): 

2755 """ 

2756 Computes the adjacency distance between two permutations. 

2757 

2758 Explanation 

2759 =========== 

2760 

2761 This metric counts the number of times a pair i,j of jobs is 

2762 adjacent in both p and p'. If n_adj is this quantity then 

2763 the adjacency distance is n - n_adj - 1 [1] 

2764 

2765 [1] Reeves, Colin R. Landscapes, Operators and Heuristic search, Annals 

2766 of Operational Research, 86, pp 473-490. (1999) 

2767 

2768 

2769 Examples 

2770 ======== 

2771 

2772 >>> from sympy.combinatorics import Permutation 

2773 >>> p = Permutation([0, 3, 1, 2, 4]) 

2774 >>> q = Permutation.josephus(4, 5, 2) 

2775 >>> p.get_adjacency_distance(q) 

2776 3 

2777 >>> r = Permutation([0, 2, 1, 4, 3]) 

2778 >>> p.get_adjacency_distance(r) 

2779 4 

2780 

2781 See Also 

2782 ======== 

2783 

2784 get_precedence_matrix, get_precedence_distance, get_adjacency_matrix 

2785 """ 

2786 if self.size != other.size: 

2787 raise ValueError("The permutations must be of the same size.") 

2788 self_adj_mat = self.get_adjacency_matrix() 

2789 other_adj_mat = other.get_adjacency_matrix() 

2790 n_adj = 0 

2791 for i in range(self.size): 

2792 for j in range(self.size): 

2793 if i == j: 

2794 continue 

2795 if self_adj_mat[i, j] * other_adj_mat[i, j] == 1: 

2796 n_adj += 1 

2797 d = self.size - n_adj - 1 

2798 return d 

2799 

2800 def get_positional_distance(self, other): 

2801 """ 

2802 Computes the positional distance between two permutations. 

2803 

2804 Examples 

2805 ======== 

2806 

2807 >>> from sympy.combinatorics import Permutation 

2808 >>> p = Permutation([0, 3, 1, 2, 4]) 

2809 >>> q = Permutation.josephus(4, 5, 2) 

2810 >>> r = Permutation([3, 1, 4, 0, 2]) 

2811 >>> p.get_positional_distance(q) 

2812 12 

2813 >>> p.get_positional_distance(r) 

2814 12 

2815 

2816 See Also 

2817 ======== 

2818 

2819 get_precedence_distance, get_adjacency_distance 

2820 """ 

2821 a = self.array_form 

2822 b = other.array_form 

2823 if len(a) != len(b): 

2824 raise ValueError("The permutations must be of the same size.") 

2825 return sum([abs(a[i] - b[i]) for i in range(len(a))]) 

2826 

2827 @classmethod 

2828 def josephus(cls, m, n, s=1): 

2829 """Return as a permutation the shuffling of range(n) using the Josephus 

2830 scheme in which every m-th item is selected until all have been chosen. 

2831 The returned permutation has elements listed by the order in which they 

2832 were selected. 

2833 

2834 The parameter ``s`` stops the selection process when there are ``s`` 

2835 items remaining and these are selected by continuing the selection, 

2836 counting by 1 rather than by ``m``. 

2837 

2838 Consider selecting every 3rd item from 6 until only 2 remain:: 

2839 

2840 choices chosen 

2841 ======== ====== 

2842 012345 

2843 01 345 2 

2844 01 34 25 

2845 01 4 253 

2846 0 4 2531 

2847 0 25314 

2848 253140 

2849 

2850 Examples 

2851 ======== 

2852 

2853 >>> from sympy.combinatorics import Permutation 

2854 >>> Permutation.josephus(3, 6, 2).array_form 

2855 [2, 5, 3, 1, 4, 0] 

2856 

2857 References 

2858 ========== 

2859 

2860 .. [1] https://en.wikipedia.org/wiki/Flavius_Josephus 

2861 .. [2] https://en.wikipedia.org/wiki/Josephus_problem 

2862 .. [3] https://web.archive.org/web/20171008094331/http://www.wou.edu/~burtonl/josephus.html 

2863 

2864 """ 

2865 from collections import deque 

2866 m -= 1 

2867 Q = deque(list(range(n))) 

2868 perm = [] 

2869 while len(Q) > max(s, 1): 

2870 for dp in range(m): 

2871 Q.append(Q.popleft()) 

2872 perm.append(Q.popleft()) 

2873 perm.extend(list(Q)) 

2874 return cls(perm) 

2875 

2876 @classmethod 

2877 def from_inversion_vector(cls, inversion): 

2878 """ 

2879 Calculates the permutation from the inversion vector. 

2880 

2881 Examples 

2882 ======== 

2883 

2884 >>> from sympy.combinatorics import Permutation 

2885 >>> from sympy import init_printing 

2886 >>> init_printing(perm_cyclic=False, pretty_print=False) 

2887 >>> Permutation.from_inversion_vector([3, 2, 1, 0, 0]) 

2888 Permutation([3, 2, 1, 0, 4, 5]) 

2889 

2890 """ 

2891 size = len(inversion) 

2892 N = list(range(size + 1)) 

2893 perm = [] 

2894 try: 

2895 for k in range(size): 

2896 val = N[inversion[k]] 

2897 perm.append(val) 

2898 N.remove(val) 

2899 except IndexError: 

2900 raise ValueError("The inversion vector is not valid.") 

2901 perm.extend(N) 

2902 return cls._af_new(perm) 

2903 

2904 @classmethod 

2905 def random(cls, n): 

2906 """ 

2907 Generates a random permutation of length ``n``. 

2908 

2909 Uses the underlying Python pseudo-random number generator. 

2910 

2911 Examples 

2912 ======== 

2913 

2914 >>> from sympy.combinatorics import Permutation 

2915 >>> Permutation.random(2) in (Permutation([1, 0]), Permutation([0, 1])) 

2916 True 

2917 

2918 """ 

2919 perm_array = list(range(n)) 

2920 random.shuffle(perm_array) 

2921 return cls._af_new(perm_array) 

2922 

2923 @classmethod 

2924 def unrank_lex(cls, size, rank): 

2925 """ 

2926 Lexicographic permutation unranking. 

2927 

2928 Examples 

2929 ======== 

2930 

2931 >>> from sympy.combinatorics import Permutation 

2932 >>> from sympy import init_printing 

2933 >>> init_printing(perm_cyclic=False, pretty_print=False) 

2934 >>> a = Permutation.unrank_lex(5, 10) 

2935 >>> a.rank() 

2936 10 

2937 >>> a 

2938 Permutation([0, 2, 4, 1, 3]) 

2939 

2940 See Also 

2941 ======== 

2942 

2943 rank, next_lex 

2944 """ 

2945 perm_array = [0] * size 

2946 psize = 1 

2947 for i in range(size): 

2948 new_psize = psize*(i + 1) 

2949 d = (rank % new_psize) // psize 

2950 rank -= d*psize 

2951 perm_array[size - i - 1] = d 

2952 for j in range(size - i, size): 

2953 if perm_array[j] > d - 1: 

2954 perm_array[j] += 1 

2955 psize = new_psize 

2956 return cls._af_new(perm_array) 

2957 

2958 def resize(self, n): 

2959 """Resize the permutation to the new size ``n``. 

2960 

2961 Parameters 

2962 ========== 

2963 

2964 n : int 

2965 The new size of the permutation. 

2966 

2967 Raises 

2968 ====== 

2969 

2970 ValueError 

2971 If the permutation cannot be resized to the given size. 

2972 This may only happen when resized to a smaller size than 

2973 the original. 

2974 

2975 Examples 

2976 ======== 

2977 

2978 >>> from sympy.combinatorics import Permutation 

2979 

2980 Increasing the size of a permutation: 

2981 

2982 >>> p = Permutation(0, 1, 2) 

2983 >>> p = p.resize(5) 

2984 >>> p 

2985 (4)(0 1 2) 

2986 

2987 Decreasing the size of the permutation: 

2988 

2989 >>> p = p.resize(4) 

2990 >>> p 

2991 (3)(0 1 2) 

2992 

2993 If resizing to the specific size breaks the cycles: 

2994 

2995 >>> p.resize(2) 

2996 Traceback (most recent call last): 

2997 ... 

2998 ValueError: The permutation cannot be resized to 2 because the 

2999 cycle (0, 1, 2) may break. 

3000 """ 

3001 aform = self.array_form 

3002 l = len(aform) 

3003 if n > l: 

3004 aform += list(range(l, n)) 

3005 return Permutation._af_new(aform) 

3006 

3007 elif n < l: 

3008 cyclic_form = self.full_cyclic_form 

3009 new_cyclic_form = [] 

3010 for cycle in cyclic_form: 

3011 cycle_min = min(cycle) 

3012 cycle_max = max(cycle) 

3013 if cycle_min <= n-1: 

3014 if cycle_max > n-1: 

3015 raise ValueError( 

3016 "The permutation cannot be resized to {} " 

3017 "because the cycle {} may break." 

3018 .format(n, tuple(cycle))) 

3019 

3020 new_cyclic_form.append(cycle) 

3021 return Permutation(new_cyclic_form) 

3022 

3023 return self 

3024 

3025 # XXX Deprecated flag 

3026 print_cyclic = None 

3027 

3028 

3029def _merge(arr, temp, left, mid, right): 

3030 """ 

3031 Merges two sorted arrays and calculates the inversion count. 

3032 

3033 Helper function for calculating inversions. This method is 

3034 for internal use only. 

3035 """ 

3036 i = k = left 

3037 j = mid 

3038 inv_count = 0 

3039 while i < mid and j <= right: 

3040 if arr[i] < arr[j]: 

3041 temp[k] = arr[i] 

3042 k += 1 

3043 i += 1 

3044 else: 

3045 temp[k] = arr[j] 

3046 k += 1 

3047 j += 1 

3048 inv_count += (mid -i) 

3049 while i < mid: 

3050 temp[k] = arr[i] 

3051 k += 1 

3052 i += 1 

3053 if j <= right: 

3054 k += right - j + 1 

3055 j += right - j + 1 

3056 arr[left:k + 1] = temp[left:k + 1] 

3057 else: 

3058 arr[left:right + 1] = temp[left:right + 1] 

3059 return inv_count 

3060 

3061Perm = Permutation 

3062_af_new = Perm._af_new 

3063 

3064 

3065class AppliedPermutation(Expr): 

3066 """A permutation applied to a symbolic variable. 

3067 

3068 Parameters 

3069 ========== 

3070 

3071 perm : Permutation 

3072 x : Expr 

3073 

3074 Examples 

3075 ======== 

3076 

3077 >>> from sympy import Symbol 

3078 >>> from sympy.combinatorics import Permutation 

3079 

3080 Creating a symbolic permutation function application: 

3081 

3082 >>> x = Symbol('x') 

3083 >>> p = Permutation(0, 1, 2) 

3084 >>> p.apply(x) 

3085 AppliedPermutation((0 1 2), x) 

3086 >>> _.subs(x, 1) 

3087 2 

3088 """ 

3089 def __new__(cls, perm, x, evaluate=None): 

3090 if evaluate is None: 

3091 evaluate = global_parameters.evaluate 

3092 

3093 perm = _sympify(perm) 

3094 x = _sympify(x) 

3095 

3096 if not isinstance(perm, Permutation): 

3097 raise ValueError("{} must be a Permutation instance." 

3098 .format(perm)) 

3099 

3100 if evaluate: 

3101 if x.is_Integer: 

3102 return perm.apply(x) 

3103 

3104 obj = super().__new__(cls, perm, x) 

3105 return obj 

3106 

3107 

3108@dispatch(Permutation, Permutation) 

3109def _eval_is_eq(lhs, rhs): 

3110 if lhs._size != rhs._size: 

3111 return None 

3112 return lhs._array_form == rhs._array_form