# HG changeset patch
# User darij grinberg <darijgrinberg@gmail.com>
# Date 1375120438 25200
# Node ID aed403aadf7c282d83d42eb084e8dde6e4c2ec04
# Parent e3a9833b4d47d4fdc055b9fd24d647cb36565478
trac #14542: review patch
diff --git a/sage/combinat/species/generating_series.py b/sage/combinat/species/generating_series.py
a
|
b
|
class CycleIndexSeries(LazyPowerSeries): |
597 | 597 | yield res |
598 | 598 | n += 1 |
599 | 599 | |
600 | | def arithmetic_product(self, g): |
| 600 | def arithmetic_product(self, g, check_input = True): |
601 | 601 | """ |
602 | | Returns the arithmetic product of ``self`` with ``g``. |
603 | | |
| 602 | Return the arithmetic product of ``self`` with ``g``. |
| 603 | |
604 | 604 | For species `M` and `N` such that `M[\\varnothing] = N[\\varnothing] = \\varnothing`, |
605 | 605 | their arithmetic product is the species `M \\boxdot N` of "`M`-assemblies of cloned `N`-structures". |
606 | 606 | This operation is defined and several examples are given in [MM]_. |
607 | 607 | |
608 | 608 | The cycle index series for `M \\boxdot N` can be computed in terms of the component series `Z_M` and `Z_N`, |
609 | 609 | as implemented in this method. |
610 | | |
| 610 | |
| 611 | INPUT: |
| 612 | |
| 613 | - ``g`` -- a cycle index series having the same parent as ``self``. |
| 614 | |
| 615 | - ``check_input`` -- (default: ``True``) a Boolean which, when set |
| 616 | to ``False``, will cause input checks to be skipped. |
| 617 | |
| 618 | OUTPUT: |
| 619 | |
| 620 | The arithmetic product of ``self`` with ``g``. This is a cycle |
| 621 | index series defined in terms of ``self`` and ``g`` such that |
| 622 | if ``self`` and ``g`` are the cycle index series of two species |
| 623 | `M` and `N`, their arithmetic product is the cycle index series |
| 624 | of the species `M \\boxdot N`. |
| 625 | |
611 | 626 | EXAMPLES: |
612 | 627 | |
613 | 628 | For `C` the species of (oriented) cycles and `L_{+}` the species of nonempty linear orders, `C \\boxdot L_{+}` corresponds |
… |
… |
class CycleIndexSeries(LazyPowerSeries): |
635 | 650 | |
636 | 651 | REFERENCES: |
637 | 652 | |
638 | | .. [MM] M. Maia and M. Mendez. "On the arithmetic product of combinatorial species." Discrete Mathematics, vol. 308, issue 23, 2008, pp. 5407-5427. |
639 | | http://arxiv.org/abs/math/0503436. |
| 653 | .. [MM] M. Maia and M. Mendez. "On the arithmetic product of combinatorial species". |
| 654 | Discrete Mathematics, vol. 308, issue 23, 2008, pp. 5407-5427. |
| 655 | :arXiv:`math/0503436v2`. |
640 | 656 | |
641 | 657 | """ |
642 | 658 | from sage.combinat.partition import Partition, Partitions |
… |
… |
class CycleIndexSeries(LazyPowerSeries): |
646 | 662 | |
647 | 663 | p = self.base_ring() |
648 | 664 | |
649 | | assert self.coefficient(0) == p.zero() |
650 | | assert g.coefficient(0) == p.zero() |
| 665 | if check_input: |
| 666 | assert self.coefficient(0) == p.zero() |
| 667 | assert g.coefficient(0) == p.zero() |
651 | 668 | |
652 | 669 | # We first define an operation `\\boxtimes` on partitions as in Lemma 2.1 of [MM]_. |
653 | | def arith_prod_of_partitions (l1, l2): |
| 670 | def arith_prod_of_partitions(l1, l2): |
654 | 671 | # Given two partitions `l_1` and `l_2`, we construct a new partition `l_1 \\boxtimes l_2` by |
655 | | # the following procedure: each pair of parts `a \\in l_1` and `b \\in l_2` contributes a part |
656 | | # `\\lcm (a, b)` to `l_1 \\boxtimes l_2` with multiplicity `\\gcm (l_1, l_2)``. |
| 672 | # the following procedure: each pair of parts `a \\in l_1` and `b \\in l_2` contributes |
| 673 | # `\\gcd (a, b)`` parts of size `\\lcm (a, b)` to `l_1 \\boxtimes l_2`. If `l_1` and `l_2` |
| 674 | # are partitions of integers `n` and `m`, respectively, then `l_1 \\boxtimes l_2` is a |
| 675 | # partition of `nm`. |
657 | 676 | term_iterable = chain.from_iterable( repeat(lcm(pair), times=gcd(pair)) for pair in product(l1, l2) ) |
658 | 677 | term_list = sorted(term_iterable, reverse=True) |
659 | 678 | res = Partition(term_list) |
660 | 679 | return res |
661 | 680 | |
662 | | # We then extend this to an operation on symmetric functions as per eq. 52 of [MM]_. |
663 | | def arith_prod_sf (x, y): |
| 681 | # We then extend this to an operation on symmetric functions as per eq. (52) of [MM]_. |
| 682 | # (Maia and Mendez, in [MM]_, are talking about polynomials instead of symmetric |
| 683 | # functions, but this boils down to the same: Their x_i corresponds to the i-th power |
| 684 | # sum symmetric function.) |
| 685 | def arith_prod_sf(x, y): |
664 | 686 | ap_sf_wrapper = lambda l1, l2: p(arith_prod_of_partitions(l1, l2)) |
665 | 687 | return p._apply_multi_module_morphism(x, y, ap_sf_wrapper) |
666 | 688 | |
667 | 689 | # Sage stores cycle index series by degree. |
668 | 690 | # Thus, to compute the arithmetic product `Z_M \\boxdot Z_N` it is useful |
669 | 691 | # to compute all terms of a given degree `n` at once. |
670 | | def arith_prod_coeff (n): |
| 692 | def arith_prod_coeff(n): |
671 | 693 | if n == 0: |
672 | 694 | res = p.zero() |
673 | 695 | else: |
674 | | index_set = ((d, n/d) for d in divisors(n)) |
| 696 | index_set = ((d, n // d) for d in divisors(n)) |
675 | 697 | res = sum(arith_prod_sf(self.coefficient(i), g.coefficient(j)) for i,j in index_set) |
676 | 698 | |
677 | | # Build a list which has res in the nth slot and 0's before and after |
| 699 | # Build a list which has res in the `n`th slot and 0's before and after |
678 | 700 | # to feed to sum_generator |
679 | 701 | res_in_seq = [p.zero()]*n + [res, p.zero()] |
680 | 702 | |