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))
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)
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)
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
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)
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)
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)