def _generate_partition_f(self, a, b, k):
        r"""
        Generate a new partition for a given value of `a` by updating the
        vacancy numbers and preserving co-labels for the map `f_a`.

        INPUT:

        - ``a`` -- The index of the partition we operated on.
        - ``b`` -- The index of the partition to generate.
        - ``k`` -- The length of the string with smallest nonpositive rigging of largest length.

        OUTPUT:

        - The constructed rigged partition.

        TESTS::
        
            sage: RC = RiggedConfigurations(['A', 4, 1], [[2,1]])
            sage: RC(partition_list=[[1], [1], [1], [1]])._generate_partition_f(1, 2, 1)
            0[ ]0
            <BLANKLINE>
        """
        #cartan_matrix = self.parent()._cartan_type.classical().cartan_matrix()
        cartan_matrix = self.parent()._cartan_type.cartan_matrix()
        # Check to make sure we will do something
        if cartan_matrix[a][b] == 0:
            return self[b]

        new_list = self[b][:]
        new_vac_nums = self[b].vacancy_numbers[:]
        new_rigging = self[b].rigging[:]

        # Update the vacancy numbers and the rigging
        value = cartan_matrix[a][b]
        for i in range(len(new_vac_nums)):
            if new_list[i] <= k:
                break

            new_vac_nums[i] -= value
            new_rigging[i] -= value

        return (RiggedPartition(new_list, new_rigging, new_vac_nums))
Пример #2
0
    def _generate_partition_e(self, a, b, k):
        r"""
        Generate a new partition for a given value of `a` by updating the
        vacancy numbers and preserving co-labels for the map `e_a`.

        INPUT:

        - ``a`` -- the index of the partition we operated on
        - ``b`` -- the index of the partition to generate
        - ``k`` -- the length of the string with the smallest negative
          rigging of smallest length

        OUTPUT:

        The constructed rigged partition.

        TESTS::

            sage: RC = RiggedConfigurations(['A', 4, 1], [[2,1]])
            sage: RC(partition_list=[[1], [1], [1], [1]])._generate_partition_e(1, 2, 1)
            -1[ ]-1
            <BLANKLINE>
        """
        # Check to make sure we will do something
        if self.parent()._cartan_matrix[a][b] == 0:
            return self[b]

        new_list = self[b][:]
        new_vac_nums = self[b].vacancy_numbers[:]
        new_rigging = self[b].rigging[:]

        # Update the vacancy numbers and the rigging
        value = self.parent()._cartan_matrix[a][b]
        for i in range(len(new_vac_nums)):
            if new_list[i] < k:
                break

            new_vac_nums[i] += value
            new_rigging[i] += value

        return(RiggedPartition(new_list, new_rigging, new_vac_nums))
    def f(self, a):
        r"""
        Action of crystal operator `f_a` on this rigged configuration element.

        This implements the method defined in [CrysStructSchilling06]_ which
        finds the value `k` which is  the length of the string with the
        smallest nonpositive rigging of largest length. Then it adds a box from
        a string of length `k` in the `a`-th rigged partition, keeping all
        colabels fixed and decreasing the new label by one. If no such string
        exists, then it adds a new string of length 1 with label `-1`. If any
        of the resulting vacancy numbers are larger than the labels (i.e. it
        is an invalid rigged configuration), then `f_a` is undefined.

        INPUT:

        - ``a`` -- The index of the partition to add a box.

        OUTPUT:

        - The resulting rigged configuration element.

        EXAMPLES::

            sage: RC = RiggedConfigurations(['A', 4, 1], [[2,1]])
            sage: elt = RC(partition_list=[[1], [1], [1], [1]])
            sage: elt.f(1)
            sage: elt.f(2)
            <BLANKLINE>
            0[ ]0
            <BLANKLINE>
            -1[ ]-1
            -1[ ]-1
            <BLANKLINE>
            1[ ]1
            <BLANKLINE>
            -1[ ]-1
            <BLANKLINE>
        """
        assert a in self.parent()._cartan_type.index_set()
        if a == 0:
            raise NotImplementedError(
                "Only classical crystal operators implemented")

        a -= 1  # For indexing

        new_list = self[a][:]
        new_vac_nums = self[a].vacancy_numbers[:]
        new_rigging = self[a].rigging[:]

        # Find k and perform f_a
        k = None
        add_index = -1  # Index where we will add our row too
        rigging_index = None  # Index which we will pull the rigging from
        cur_rigging = 0
        num_rows = len(new_list)
        for i in reversed(range(num_rows)):
            # If we need to increment a row, look for when we change rows for
            #   the correct index.
            if add_index is None and new_list[i] != new_list[rigging_index]:
                add_index = i + 1

            if new_rigging[i] <= cur_rigging:
                cur_rigging = new_rigging[i]
                k = new_list[i]
                rigging_index = i
                add_index = None

        # If we've not found a valid k
        if k is None:
            new_list.append(1)
            new_rigging.append(-1)
            new_vac_nums.append(None)
            k = 0
            add_index = num_rows
            num_rows += 1  # We've added a row
        else:
            if add_index is None:  # We are adding to the first row in the list
                add_index = 0
            new_list[add_index] += 1
            new_rigging.insert(add_index, new_rigging[rigging_index] - 1)
            new_vac_nums.insert(add_index, None)
            new_rigging.pop(rigging_index + 1)  # add 1 for the insertion
            new_vac_nums.pop(rigging_index + 1)

        new_partitions = []
        for b in range(len(self)):
            if b != a:
                new_partitions.append(self._generate_partition_f(a, b, k))
            else:
                # Update the vacancy numbers and the rigging
                for i in range(num_rows):
                    if new_list[i] <= k:
                        break

                    if i != add_index:
                        new_vac_nums[i] -= 2
                        new_rigging[i] -= 2

                new_partitions.append(
                    RiggedPartition(new_list, new_rigging, new_vac_nums))

        new_partitions[a].vacancy_numbers[add_index] = \
          self.parent()._calc_vacancy_number(new_partitions, a, add_index)
        if new_partitions[a].rigging[add_index] > new_partitions[
                a].vacancy_numbers[add_index]:
            return None

        # Note that we do not need to sort the rigging since if there was a
        #   smaller rigging in a larger row, then `k` would be larger.
        from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations
        #return self.__class__(RiggedConfigurations(self.parent()._cartan_type, self.parent().dims),
        return self.__class__(
            RiggedConfigurations(self.parent()._affine_ct,
                                 self.parent().dims), *new_partitions)
    def e(self, a):
        r"""
        Action of the crystal operator `e_a` on this rigged configuration element.

        This implements the method defined in [CrysStructSchilling06]_ which
        finds the value `k` which is  the length of the string with the
        smallest negative rigging of smallest length. Then it removes a box
        from a string of length `k` in the `a`-th rigged partition, keeping all
        colabels fixed and increasing the new label by one. If no such string
        exists, then `e_a` is undefined.

        INPUT:

        - ``a`` -- The index of the partition to remove a box.

        OUTPUT:

        - The resulting rigged configuration element.

        EXAMPLES::

            sage: RC = RiggedConfigurations(['A', 4, 1], [[2,1]])
            sage: elt = RC(partition_list=[[1], [1], [1], [1]])
            sage: elt.e(3)
            sage: elt.e(1)
            <BLANKLINE>
            (/)
            <BLANKLINE>
            0[ ]0
            <BLANKLINE>
            0[ ]0
            <BLANKLINE>
            -1[ ]-1
            <BLANKLINE>
        """
        assert a in self.parent()._cartan_type.index_set()
        if a == 0:
            raise NotImplementedError(
                "Only classical crystal operators implemented")

        a -= 1  # For indexing

        new_list = self[a][:]
        new_vac_nums = self[a].vacancy_numbers[:]
        new_rigging = self[a].rigging[:]

        # Find k and perform e_a
        k = None
        num_rows = len(new_list)
        cur_rigging = -1
        rigging_index = None
        for i in range(num_rows):
            if new_rigging[i] <= cur_rigging:
                cur_rigging = new_rigging[i]
                rigging_index = i

        # If we've not found a valid k
        if rigging_index is None:
            return None

        # Note that because the riggings are weakly decreasing, we will always
        #   remove the last box on of a block
        k = new_list[rigging_index]
        if k == 1:
            new_list.pop()
            new_vac_nums.pop()
            new_rigging.pop()
        else:
            new_list[rigging_index] -= 1
            cur_rigging += 1
            # Properly sort the riggings
            j = rigging_index + 1
            while j < num_rows and new_list[j] == new_list[rigging_index] \
              and new_rigging[j] > cur_rigging:
                new_rigging[j - 1] = new_rigging[j]  # Shuffle it along
                j += 1
            new_rigging[j - 1] = cur_rigging

        new_partitions = []
        for b in range(len(self)):
            if b != a:
                new_partitions.append(self._generate_partition_e(a, b, k))
            else:
                # Update the vacancy numbers and the rigging
                for i in range(len(new_vac_nums)):
                    if new_list[i] < k:
                        break

                    new_vac_nums[i] += 2
                    new_rigging[i] += 2

                if k != 1:  # If we did not remove a row
                    new_vac_nums[rigging_index] += 2

                new_partitions.append(
                    RiggedPartition(new_list, new_rigging, new_vac_nums))

        from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations
        #ret_RC = self.__class__(RiggedConfigurations(self.parent()._cartan_type, self.parent().dims),
        ret_RC = self.__class__(
            RiggedConfigurations(self.parent()._affine_ct,
                                 self.parent().dims), *new_partitions)
        if k != 1:  # If we did not remove a row
            # Update that row's vacancy number
            ret_RC[a].vacancy_numbers[rigging_index] = \
              self.parent()._calc_vacancy_number(ret_RC.nu(), a, rigging_index)
        return (ret_RC)
    def __init__(self, parent, *rigged_partitions, **options):
        r"""
        Construct a rigged configuration element.

        INPUT:

        - ``parent``            -- The parent of this element
        - ``rigged_partitions`` -- A list of rigged partitions

        There are two optional arguments to explicitly construct a rigged
        configuration. The first is **partition_list** which gives a list of
        partitions, and the second is **rigging_list** which is a list of
        corresponding lists of riggings. If only partition_list is specified,
        then it sets the rigging equal to the calculated vacancy numbers.

        EXAMPLES::

            sage: RC = RiggedConfigurations(['A', 4, 1], [[2, 1]])
            sage: RC(partition_list=[[], [], [], []])
            <BLANKLINE>
            (/)
            <BLANKLINE>
            (/)
            <BLANKLINE>
            (/)
            <BLANKLINE>
            (/)
            <BLANKLINE>
            sage: RC(partition_list=[[1], [1], [], []])
            <BLANKLINE>
            -1[ ]-1
            <BLANKLINE>
            0[ ]0
            <BLANKLINE>
            (/)
            <BLANKLINE>
            (/)
            <BLANKLINE>
            sage: elt = RC(partition_list=[[1], [1], [], []], rigging_list=[[-1], [0], [], []]); elt
            <BLANKLINE>
            -1[ ]-1
            <BLANKLINE>
            0[ ]0
            <BLANKLINE>
            (/)
            <BLANKLINE>
            (/)
            <BLANKLINE>
            sage: TestSuite(elt).run()
        """

        if "partition_list" in options:
            data = options["partition_list"]
            n = parent._cartan_type.n
            if len(data) == 0:
                # Create a size n array of empty rigged tableau since no tableau
                #   were given
                nu = []
                for i in range(parent._cartan_type.n):
                    nu.append(RiggedPartition())
            else:
                if len(
                        data
                ) != n:  # otherwise n should be equal to the number of tableaux
                    raise ValueError

                nu = []
                if "rigging_list" in options:
                    rigging_data = options["rigging_list"]

                    if len(rigging_data) != n:
                        raise ValueError

                    for i in range(parent._cartan_type.n):
                        nu.append(RiggedPartition(tuple(data[i]), \
                           list(rigging_data[i])))
                else:
                    for partition_data in data:
                        nu.append(RiggedPartition(tuple(partition_data)))
        elif len(list(rigged_partitions)) == 0:
            # Create a size n array of empty rigged tableau since no tableau
            #   were given
            nu = []
            for i in range(parent._cartan_type.n):
                nu.append(RiggedPartition())
        elif "KT_constructor" in options:
            # Used only by the Kleber tree
            # Not recommended to be called by the user since it avoids safety
            #   checks for speed
            data = options["KT_constructor"]
            shape_data = data[0]
            rigging_data = data[1]
            vac_data = data[2]
            nu = []
            for i in range(parent._cartan_type.n):
                nu.append(
                    RiggedPartition(shape_data[i], rigging_data[i],
                                    vac_data[i]))
            ClonableArray.__init__(self, parent, nu)
            return
        elif parent._cartan_type.n == len(list(rigged_partitions)):
            ClonableArray.__init__(self, parent, list(rigged_partitions))
            return
        else:
            # Otherwise we did not receive any info, create a size n array of
            #   empty rigged partitions
            nu = []
            for i in range(parent._cartan_type.n):
                nu.append(RiggedPartition())

        # Set the vacancy numbers
        for a, partition in enumerate(nu):
            # If the partition is empty, there's nothing to do
            if len(partition) <= 0:
                continue

            # Setup the first block
            block_len = partition[0]
            vac_num = parent._calc_vacancy_number(nu, a, 0)

            for i, row_len in enumerate(partition):
                # If we've gone to a different sized block, then update the
                #   values which change when moving to a new block size
                if block_len != row_len:
                    vac_num = parent._calc_vacancy_number(nu, a, i)
                    block_len = row_len

                partition.vacancy_numbers[i] = vac_num
                if partition.rigging[i] is None:
                    partition.rigging[i] = partition.vacancy_numbers[i]

        ClonableArray.__init__(self, parent, nu)
Пример #6
0
    def run(self, verbose=False):
        """
        Run the bijection from rigged configurations to tensor product of KR
        tableaux for type `B_n^{(1)}`.

        INPUT:

        - ``verbose`` -- (Default: ``False``) Display each step in the
          bijection

        EXAMPLES::

            sage: RC = RiggedConfigurations(['B', 3, 1], [[2, 1]])
            sage: from sage.combinat.rigged_configurations.bij_type_B import RCToKRTBijectionTypeB
            sage: RCToKRTBijectionTypeB(RC(partition_list=[[1],[1,1],[1]])).run()
            [[3], [0]]
            sage: RC = RiggedConfigurations(['B', 3, 1], [[3, 1]])
            sage: from sage.combinat.rigged_configurations.bij_type_B import RCToKRTBijectionTypeB
            sage: RCToKRTBijectionTypeB(RC(partition_list=[[],[1],[1]])).run()
            [[1], [3], [-2]]
        """
        from sage.combinat.crystals.letters import CrystalOfLetters
        letters = CrystalOfLetters(
            self.rigged_con.parent()._cartan_type.classical())

        # This is technically bad, but because the first thing we do is append
        #   an empty list to ret_crystal_path, we correct this. We do it this
        #   way so that we do not have to remove an empty list after the
        #   bijection has been performed.
        ret_crystal_path = []

        for dim in self.rigged_con.parent().dims:
            ret_crystal_path.append([])

            # Check to see if we are a spinor
            if dim[0] == self.n:
                # Perform the spinor bijection by converting to type A_{2n-1}^{(2)}
                #   doing the bijection there and pulling back

                from sage.combinat.rigged_configurations.bij_type_A2_odd import RCToKRTBijectionTypeA2Odd
                from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations
                from sage.combinat.rigged_configurations.rigged_partition import RiggedPartition, RiggedPartitionTypeB

                # Convert to a type A_{2n-1}^{(2)} RC
                RC = RiggedConfigurations(['A', 2 * self.n - 1, 2],
                                          self.cur_dims)
                if verbose:
                    print("====================")
                    print(repr(RC(*self.cur_partitions)))
                    print("--------------------")
                    print(ret_crystal_path)
                    print("--------------------\n")
                    print("Applying doubling map\n")
                # Convert the n-th partition into a regular rigged partition
                self.cur_partitions[-1] = RiggedPartition(
                    self.cur_partitions[-1]._list,
                    self.cur_partitions[-1].rigging,
                    self.cur_partitions[-1].vacancy_numbers)

                bij = RCToKRTBijectionTypeA2Odd(RC(*self.cur_partitions))
                for i in range(len(self.cur_dims)):
                    if bij.cur_dims[i][0] != self.n:
                        bij.cur_dims[i][1] *= 2
                for i in range(self.n - 1):
                    for j in range(len(bij.cur_partitions[i])):
                        bij.cur_partitions[i]._list[j] *= 2
                        bij.cur_partitions[i].rigging[j] *= 2
                        bij.cur_partitions[i].vacancy_numbers[j] *= 2

                # Perform the type A_{2n-1}^{(2)} bijection

                # Iterate over each column
                for dummy_var in range(dim[1]):
                    # Split off a new column if necessary
                    if bij.cur_dims[0][1] > 1:
                        bij.cur_dims[0][1] -= 1
                        bij.cur_dims.insert(0, [dim[0], 1])

                        # Perform the corresponding splitting map on rigged configurations
                        # All it does is update the vacancy numbers on the RC side
                        for a in range(self.n):
                            bij._update_vacancy_numbers(a)

                    while bij.cur_dims[0][0] > 0:
                        if verbose:
                            print("====================")
                            print(repr(RC(*bij.cur_partitions)))
                            print("--------------------")
                            print(ret_crystal_path)
                            print("--------------------\n")

                        bij.cur_dims[0][
                            0] -= 1  # This takes care of the indexing
                        b = bij.next_state(bij.cur_dims[0][0])
                        # Make sure we have a crystal letter
                        ret_crystal_path[-1].append(
                            letters(b))  # Append the rank

                    bij.cur_dims.pop(0)  # Pop off the leading column

                self.cur_dims.pop(0)  # Pop off the spin rectangle

                self.cur_partitions = bij.cur_partitions
                # Convert the n-th partition back into the special type B one
                self.cur_partitions[-1] = RiggedPartitionTypeB(
                    self.cur_partitions[-1])

                # Convert back to a type B_n^{(1)}
                if verbose:
                    print("====================")
                    print(repr(self.rigged_con.parent()(*bij.cur_partitions)))
                    print("--------------------")
                    print(ret_crystal_path)
                    print("--------------------\n")
                    print("Applying halving map\n")

                for i in range(self.n - 1):
                    for j in range(len(self.cur_partitions[i])):
                        self.cur_partitions[i]._list[j] //= 2
                        self.cur_partitions[i].rigging[j] //= 2
                        self.cur_partitions[i].vacancy_numbers[j] //= 2
            else:
                # Perform the regular type B_n^{(1)} bijection

                # Iterate over each column
                for dummy_var in range(dim[1]):
                    # Split off a new column if necessary
                    if self.cur_dims[0][1] > 1:
                        if verbose:
                            print("====================")
                            print(
                                repr(self.rigged_con.parent()(
                                    *self.cur_partitions)))
                            print("--------------------")
                            print(ret_crystal_path)
                            print("--------------------\n")
                            print("Applying column split")

                        self.cur_dims[0][1] -= 1
                        self.cur_dims.insert(0, [dim[0], 1])

                        # Perform the corresponding splitting map on rigged configurations
                        # All it does is update the vacancy numbers on the RC side
                        for a in range(self.n):
                            self._update_vacancy_numbers(a)

                    while self.cur_dims[0][0] > 0:
                        if verbose:
                            print("====================")
                            print(
                                repr(self.rigged_con.parent()(
                                    *self.cur_partitions)))
                            print("--------------------")
                            print(ret_crystal_path)
                            print("--------------------\n")

                        self.cur_dims[0][
                            0] -= 1  # This takes care of the indexing
                        b = self.next_state(self.cur_dims[0][0])

                        # Make sure we have a crystal letter
                        ret_crystal_path[-1].append(
                            letters(b))  # Append the rank

                    self.cur_dims.pop(0)  # Pop off the leading column

        return self.KRT(pathlist=ret_crystal_path)
Пример #7
0
    def run(self, verbose=False):
        """
        Run the bijection from a tensor product of KR tableaux to a rigged
        configuration.

        INPUT:

        - ``tp_krt`` -- A tensor product of KR tableaux

        - ``verbose`` -- (Default: ``False``) Display each step in the
          bijection

        EXAMPLES::

            sage: from sage.combinat.rigged_configurations.bij_type_B import KRTToRCBijectionTypeB
            sage: KRT = TensorProductOfKirillovReshetikhinTableaux(['B', 3, 1], [[2, 1]])
            sage: KRTToRCBijectionTypeB(KRT(pathlist=[[0,3]])).run()
            <BLANKLINE>
            0[ ]0
            <BLANKLINE>
            -1[ ]-1
            -1[ ]-1
            <BLANKLINE>
            0[]0
            <BLANKLINE>
            sage: KRT = TensorProductOfKirillovReshetikhinTableaux(['B', 3, 1], [[3, 1]])
            sage: KRTToRCBijectionTypeB(KRT(pathlist=[[-2,3,1]])).run()
            <BLANKLINE>
            (/)
            <BLANKLINE>
            -1[ ]-1
            <BLANKLINE>
            0[]0
            <BLANKLINE>
        """
        if verbose:
            from sage.combinat.rigged_configurations.tensor_product_kr_tableaux_element \
              import TensorProductOfKirillovReshetikhinTableauxElement

        for cur_crystal in reversed(self.tp_krt):
            r = cur_crystal.parent().r()

            # Check if it is a spinor
            if r == self.n:
                # Perform the spinor bijection by converting to type A_{2n-1}^{(2)}
                #   doing the bijection there and pulling back
                from sage.combinat.rigged_configurations.bij_type_A2_odd import KRTToRCBijectionTypeA2Odd
                from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import TensorProductOfKirillovReshetikhinTableaux
                from sage.combinat.rigged_configurations.rigged_partition import RiggedPartition

                if verbose:
                    print "===================="
                    if len(self.cur_path) == 0:
                        print(
                            repr([])
                        )  # Special case for displaying when the rightmost factor is a spinor
                    else:
                        print(
                            repr(
                                TensorProductOfKirillovReshetikhinTableauxElement(
                                    self.tp_krt.parent(), self.cur_path)))
                    print("--------------------")
                    print(repr(self.ret_rig_con))
                    print("--------------------\n")
                    print("Applying doubling map")

                # Convert to a type A_{2n-1}^{(2)} RC
                dims = self.cur_dims[:]
                dims.insert(0, [r, cur_crystal.parent().s()])
                KRT = TensorProductOfKirillovReshetikhinTableaux(
                    ['A', 2 * self.n - 1, 2], dims)
                # Convert the n-th partition into a regular rigged partition
                self.ret_rig_con[-1] = RiggedPartition(
                    self.ret_rig_con[-1]._list, self.ret_rig_con[-1].rigging,
                    self.ret_rig_con[-1].vacancy_numbers)
                bij = KRTToRCBijectionTypeA2Odd(
                    KRT.module_generators[0])  # Placeholder element
                bij.ret_rig_con = KRT.rigged_configurations()(
                    *self.ret_rig_con)
                bij.cur_path = self.cur_path
                bij.cur_dims = self.cur_dims
                for i in range(len(self.cur_dims)):
                    if bij.cur_dims[i][0] != self.n:
                        bij.cur_dims[i][1] *= 2
                for i in range(self.n - 1):
                    for j in range(len(bij.ret_rig_con[i])):
                        bij.ret_rig_con[i]._list[j] *= 2
                        bij.ret_rig_con[i].rigging[j] *= 2
                        bij.ret_rig_con[i].vacancy_numbers[j] *= 2

                # Perform the type A_{2n-1}^{(2)} bijection
                r = cur_crystal.parent().r()
                # Iterate through the columns
                for col_number, cur_column in enumerate(
                        reversed(cur_crystal.to_array(False))):
                    bij.cur_path.insert(0, [])  # Prepend an empty list
                    bij.cur_dims.insert(0, [0, 1])

                    # Note that we do not need to worry about iterating over columns
                    #   (see previous note about the data structure).
                    for letter in reversed(cur_column):
                        bij.cur_dims[0][0] += 1
                        val = letter.value  # Convert from a CrystalOfLetter to an Integer

                        if verbose:
                            print("====================")
                            print(
                                repr(
                                    TensorProductOfKirillovReshetikhinTableauxElement(
                                        self.tp_krt.parent(), bij.cur_path)))
                            print("--------------------")
                            print(repr(bij.ret_rig_con))
                            print("--------------------\n")

                        # Build the next state
                        bij.cur_path[0].insert(0,
                                               [letter])  # Prepend the value
                        bij.next_state(val)

                    # If we've split off a column, we need to merge the current column
                    #   to the current crystal tableau
                    if col_number > 0:
                        for i, letter_singleton in enumerate(self.cur_path[0]):
                            bij.cur_path[1][i].insert(0, letter_singleton[0])
                        bij.cur_dims[1][1] += 1
                        bij.cur_path.pop(0)
                        bij.cur_dims.pop(0)

                        # And perform the inverse column splitting map on the RC
                        for a in range(self.n):
                            bij._update_vacancy_nums(a)

                if verbose:
                    print("====================")
                    print(
                        repr(
                            TensorProductOfKirillovReshetikhinTableauxElement(
                                self.tp_krt.parent(), bij.cur_path)))
                    print("--------------------")
                    print(repr(bij.ret_rig_con))
                    print("--------------------\n")
                    print("Applying halving map")

                # Convert back to a type B_n^{(1)}
                for i in range(len(self.cur_dims)):
                    if bij.cur_dims[i][0] != self.n:
                        bij.cur_dims[i][1] //= 2
                for i in range(self.n - 1):
                    for j in range(len(bij.ret_rig_con[i])):
                        bij.ret_rig_con[i]._list[j] //= 2
                        bij.ret_rig_con[i].rigging[j] //= 2
                        bij.ret_rig_con[i].vacancy_numbers[j] //= 2
                self.ret_rig_con = self.tp_krt.parent().rigged_configurations(
                )(*bij.ret_rig_con)
                # Make it mutable so we don't have to keep making copies, at the
                #   end of the bijection, we will make it immutable again
                self.ret_rig_con._set_mutable()
            else:
                # Perform the regular type B_n^{(1)} bijection
                # Iterate through the columns
                for col_number, cur_column in enumerate(
                        reversed(cur_crystal.to_array(False))):
                    self.cur_path.insert(0, [])  # Prepend an empty list
                    self.cur_dims.insert(0, [0, 1])

                    # Note that we do not need to worry about iterating over columns
                    #   (see previous note about the data structure).
                    for letter in reversed(cur_column):
                        self.cur_dims[0][0] += 1
                        val = letter.value  # Convert from a CrystalOfLetter to an Integer

                        if verbose:
                            print("====================")
                            print(
                                repr(
                                    TensorProductOfKirillovReshetikhinTableauxElement(
                                        self.tp_krt.parent(), self.cur_path)))
                            print("--------------------")
                            print(repr(self.ret_rig_con))
                            print("--------------------\n")

                        # Build the next state
                        self.cur_path[0].insert(0,
                                                [letter])  # Prepend the value
                        self.next_state(val)

                    # If we've split off a column, we need to merge the current column
                    #   to the current crystal tableau
                    if col_number > 0:
                        if verbose:
                            print("====================")
                            print(
                                repr(
                                    TensorProductOfKirillovReshetikhinTableauxElement(
                                        self.tp_krt.parent(), self.cur_path)))
                            print("--------------------")
                            print(repr(self.ret_rig_con))
                            print("--------------------\n")
                            print("Applying column merge")

                        for i, letter_singleton in enumerate(self.cur_path[0]):
                            self.cur_path[1][i].insert(0, letter_singleton[0])
                        self.cur_dims[1][1] += 1
                        self.cur_path.pop(0)
                        self.cur_dims.pop(0)

                        # And perform the inverse column splitting map on the RC
                        for a in range(self.n):
                            self._update_vacancy_nums(a)
        self.ret_rig_con.set_immutable()  # Return it to immutable
        return self.ret_rig_con
Пример #8
0
    def f(self, a):
        r"""
        Action of the crystal operator `f_a` on ``self``.

        This implements the method defined in [CrysStructSchilling06]_ which
        finds the value `k` which is  the length of the string with the
        smallest nonpositive rigging of largest length. Then it adds a box from
        a string of length `k` in the `a`-th rigged partition, keeping all
        colabels fixed and decreasing the new label by one. If no such string
        exists, then it adds a new string of length 1 with label `-1`. If any
        of the resulting vacancy numbers are larger than the labels (i.e. it
        is an invalid rigged configuration), then `f_a` is undefined.

        .. TODO::

            Implement `f_0` without appealing to tensor product of
            KR tableaux.

        INPUT:

        - ``a`` -- the index of the partition to add a box

        OUTPUT:

        The resulting rigged configuration element.

        EXAMPLES::

            sage: RC = RiggedConfigurations(['A', 4, 1], [[2,1]])
            sage: elt = RC(partition_list=[[1], [1], [1], [1]])
            sage: elt.f(1)
            sage: elt.f(2)
            <BLANKLINE>
            0[ ]0
            <BLANKLINE>
            -1[ ]-1
            -1[ ]-1
            <BLANKLINE>
            1[ ]1
            <BLANKLINE>
            -1[ ]-1
            <BLANKLINE>
        """
        if a not in self.parent()._cartan_type.index_set():
            raise ValueError("{} is not in the index set".format(a))
        if a == 0:
            try:
                ret = self.to_tensor_product_of_kirillov_reshetikhin_tableaux().f(0)
                if ret is None:
                    return None
                return ret.to_rigged_configuration()
            except NotImplementedError:
                # We haven't implemented the bijection yet, so return None
                # This is to make sure we can at least view it as a classical
                #   crystal if there is no bijection.
                return None

        a -= 1 # For indexing

        new_list = self[a][:]
        new_vac_nums = self[a].vacancy_numbers[:]
        new_rigging = self[a].rigging[:]

        # Find k and perform f_a
        k = None
        add_index = -1 # Index where we will add our row too
        rigging_index = None # Index which we will pull the rigging from
        cur_rigging = 0
        num_rows = len(new_list)
        for i in reversed(range(num_rows)):
            # If we need to increment a row, look for when we change rows for
            #   the correct index.
            if add_index is None and new_list[i] != new_list[rigging_index]:
                add_index = i+1

            if new_rigging[i] <= cur_rigging:
                cur_rigging = new_rigging[i]
                k = new_list[i]
                rigging_index = i
                add_index = None

        # If we've not found a valid k
        if k is None:
            new_list.append(1)
            new_rigging.append(-1)
            new_vac_nums.append(None)
            k = 0
            add_index = num_rows
            num_rows += 1 # We've added a row
        else:
            if add_index is None: # We are adding to the first row in the list
                add_index = 0
            new_list[add_index] += 1
            new_rigging.insert(add_index, new_rigging[rigging_index] - 1)
            new_vac_nums.insert(add_index, None)
            new_rigging.pop(rigging_index + 1) # add 1 for the insertion
            new_vac_nums.pop(rigging_index + 1)

        new_partitions = []
        for b in range(len(self)):
            if b != a:
                new_partitions.append(self._generate_partition_f(a, b, k))
            else:
                # Update the vacancy numbers and the rigging
                for i in range(num_rows):
                    if new_list[i] <= k:
                        break

                    if i != add_index:
                        new_vac_nums[i] -= 2
                        new_rigging[i] -= 2

                new_partitions.append(RiggedPartition(new_list, new_rigging, new_vac_nums))

        new_partitions[a].vacancy_numbers[add_index] = \
          self.parent()._calc_vacancy_number(new_partitions, a, add_index)
        if new_partitions[a].rigging[add_index] > new_partitions[a].vacancy_numbers[add_index]:
            return None

        # Note that we do not need to sort the rigging since if there was a
        #   smaller rigging in a larger row, then `k` would be larger.
        return self.__class__(self.parent(), new_partitions)
Пример #9
0
    def e(self, a):
        r"""
        Action of the crystal operator `e_a` on ``self``.

        This implements the method defined in [CrysStructSchilling06]_ which
        finds the value `k` which is  the length of the string with the
        smallest negative rigging of smallest length. Then it removes a box
        from a string of length `k` in the `a`-th rigged partition, keeping all
        colabels fixed and increasing the new label by one. If no such string
        exists, then `e_a` is undefined.

        .. TODO::

            Implement `f_0` without appealing to tensor product of
            KR tableaux.

        INPUT:

        - ``a`` -- the index of the partition to remove a box

        OUTPUT:

        The resulting rigged configuration element.

        EXAMPLES::

            sage: RC = RiggedConfigurations(['A', 4, 1], [[2,1]])
            sage: elt = RC(partition_list=[[1], [1], [1], [1]])
            sage: elt.e(3)
            sage: elt.e(1)
            <BLANKLINE>
            (/)
            <BLANKLINE>
            0[ ]0
            <BLANKLINE>
            0[ ]0
            <BLANKLINE>
            -1[ ]-1
            <BLANKLINE>
        """
        if a not in self.parent()._cartan_type.index_set():
            raise ValueError("{} is not in the index set".format(a))
        if a == 0:
            try:
                ret = self.to_tensor_product_of_kirillov_reshetikhin_tableaux().e(0)
                if ret is None:
                    return None
                return ret.to_rigged_configuration()
            except NotImplementedError:
                # We haven't implemented the bijection yet, so return None
                # This is to make sure we can at least view it as a classical
                #   crystal if there is no bijection.
                return None

        a -= 1 # For indexing

        new_list = self[a][:]
        new_vac_nums = self[a].vacancy_numbers[:]
        new_rigging = self[a].rigging[:]

        # Find k and perform e_a
        k = None
        num_rows = len(new_list)
        cur_rigging = -1
        rigging_index = None
        for i in range(num_rows):
            if new_rigging[i] <= cur_rigging:
                cur_rigging = new_rigging[i]
                rigging_index = i

        # If we've not found a valid k
        if rigging_index is None:
            return None

        # Note that because the riggings are weakly decreasing, we will always
        #   remove the last box on of a block
        k = new_list[rigging_index]
        set_vac_num = False
        if k == 1:
            new_list.pop()
            new_vac_nums.pop()
            new_rigging.pop()
        else:
            new_list[rigging_index] -= 1
            cur_rigging += 1
            # Properly sort the riggings
            j = rigging_index + 1
            # Update the vacancy number if the row lengths are the same
            if j < num_rows and new_list[j] == new_list[rigging_index]:
                new_vac_nums[rigging_index] = new_vac_nums[j]
                set_vac_num = True
            while j < num_rows and new_list[j] == new_list[rigging_index] \
              and new_rigging[j] > cur_rigging:
                new_rigging[j-1] = new_rigging[j] # Shuffle it along
                j += 1
            new_rigging[j-1] = cur_rigging

        new_partitions = []
        for b in range(len(self)):
            if b != a:
                new_partitions.append(self._generate_partition_e(a, b, k))
            else:
                # Update the vacancy numbers and the rigging
                for i in range(len(new_vac_nums)):
                    if new_list[i] < k:
                        break

                    new_vac_nums[i] += 2
                    new_rigging[i] += 2

                
                if k != 1 and not set_vac_num: # If we did not remove a row nor found another row of length k-1
                    new_vac_nums[rigging_index] += 2

                new_partitions.append(RiggedPartition(new_list, new_rigging, new_vac_nums))

        ret_RC = self.__class__(self.parent(), new_partitions)
        if k != 1 and not set_vac_num: # If we did not remove a row nor found another row of length k-1
            # Update that row's vacancy number
            ret_RC[a].vacancy_numbers[rigging_index] = \
              self.parent()._calc_vacancy_number(ret_RC.nu(), a, rigging_index)
        return(ret_RC)
Пример #10
0
    def __init__(self, parent, rigged_partitions=[], **options):
        r"""
        Construct a rigged configuration element.

        EXAMPLES::

            sage: RC = RiggedConfigurations(['A', 4, 1], [[2, 1]])
            sage: RC(partition_list=[[], [], [], []])
            <BLANKLINE>
            (/)
            <BLANKLINE>
            (/)
            <BLANKLINE>
            (/)
            <BLANKLINE>
            (/)
            <BLANKLINE>
            sage: RC(partition_list=[[1], [1], [], []])
            <BLANKLINE>
            -1[ ]-1
            <BLANKLINE>
            0[ ]0
            <BLANKLINE>
            (/)
            <BLANKLINE>
            (/)
            <BLANKLINE>
            sage: elt = RC(partition_list=[[1], [1], [], []], rigging_list=[[-1], [0], [], []]); elt
            <BLANKLINE>
            -1[ ]-1
            <BLANKLINE>
            0[ ]0
            <BLANKLINE>
            (/)
            <BLANKLINE>
            (/)
            <BLANKLINE>
            sage: TestSuite(elt).run()
        """
        if "KT_constructor" in options:
            # Used only by the Kleber tree
            # Not recommended to be called by the user since it avoids safety
            #   checks for speed
            data = options["KT_constructor"]
            shape_data = data[0]
            rigging_data = data[1]
            vac_data = data[2]
            nu = []
            for i in range(parent._cartan_type.classical().rank()):
                nu.append(RiggedPartition(shape_data[i], rigging_data[i], vac_data[i]))
            # Special display case
            if parent.cartan_type().type() == 'B':
                nu[-1] = RiggedPartitionTypeB(nu[-1])
            ClonableArray.__init__(self, parent, nu)
            return
        elif "partition_list" in options:
            data = options["partition_list"]
            n = parent._cartan_type.classical().rank()
            if len(data) == 0:
                # Create a size n array of empty rigged tableau since no tableau
                #   were given
                nu = []
                for i in range(n):
                    nu.append(RiggedPartition())
            else:
                if len(data) != n: # otherwise n should be equal to the number of tableaux
                    raise ValueError("Incorrect number of partitions")

                nu = []
                if "rigging_list" in options:
                    rigging_data = options["rigging_list"]

                    if len(rigging_data) != n:
                        raise ValueError("Incorrect number of riggings")

                    for i in range(n):
                       nu.append(RiggedPartition(tuple(data[i]), \
                          list(rigging_data[i])))
                else:
                    for partition_data in data:
                        nu.append(RiggedPartition(tuple(partition_data)))
        elif parent._cartan_type.classical().rank() == len(rigged_partitions) and \
            isinstance(rigged_partitions[0], RiggedPartition):
            # The isinstance check is to make sure we are not in the n == 1 special case because
            #   Parent's __call__ always passes at least 1 argument to the element constructor

            # Special display case
            if parent.cartan_type().type() == 'B':
                rigged_partitions[-1] = RiggedPartitionTypeB(rigged_partitions[-1])
            ClonableArray.__init__(self, parent, rigged_partitions)
            return
        else:
            # Otherwise we did not receive any info, create a size n array of
            #   empty rigged partitions
            nu = []
            for i in range(parent._cartan_type.classical().rank()):
                nu.append(RiggedPartition())
            #raise ValueError("Invalid input")
            #raise ValueError("Incorrect number of rigged partitions")

        # Set the vacancy numbers
        for a, partition in enumerate(nu):
            # If the partition is empty, there's nothing to do
            if len(partition) <= 0:
                continue

            # Setup the first block
            block_len = partition[0]
            vac_num = parent._calc_vacancy_number(nu, a, 0)

            for i, row_len in enumerate(partition):
                # If we've gone to a different sized block, then update the
                #   values which change when moving to a new block size
                if block_len != row_len:
                    vac_num = parent._calc_vacancy_number(nu, a, i)
                    block_len = row_len

                partition.vacancy_numbers[i] = vac_num
                if partition.rigging[i] is None:
                    partition.rigging[i] = partition.vacancy_numbers[i]

        # Special display case
        if parent.cartan_type().type() == 'B':
            nu[-1] = RiggedPartitionTypeB(nu[-1])

        ClonableArray.__init__(self, parent, nu)