Path: blob/master/src/sage/combinat/composition_tableau.py
8817 views
r"""1Composition Tableaux23AUTHORS:45- Chris Berg, Jeff Ferreira (2012-9): Initial version6"""7from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets8from sage.sets.non_negative_integers import NonNegativeIntegers9from sage.sets.family import Family10from sage.misc.misc_c import prod11from sage.misc.classcall_metaclass import ClasscallMetaclass12from sage.functions.other import factorial13from sage.misc.cachefunc import cached_function14from sage.structure.element import Element15from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets16from sage.structure.parent import Parent17from sage.structure.unique_representation import UniqueRepresentation18from sage.combinat.composition import Composition, Compositions19from sage.combinat.partition import Partition20from sage.combinat.combinat import CombinatorialObject21from sage.rings.integer import Integer22from sage.combinat.backtrack import GenericBacktracker23import copy2425class CompositionTableau(CombinatorialObject, Element):26r"""27A composition tableau.2829A *composition tableau* `t` of shape `I = (I_1, \ldots, I_{\ell})` is an30array of boxes in rows, `I_i` boxes in row `i`, filled with positive31integers such that:32331) the entries in the rows of `t` weakly decrease from left to right,342) the left-most column of `t` strictly increase from top to bottom.353) Add zero entries to the rows of `t` until the resulting array is36rectangular of shape `\ell \times m`. For `1 \leq i < j \leq \ell,372 \leq k \leq m` and `(t(j,k) \neq 0`, and also if `t(j,k) \geq t(i,k))`38implies `t(j,k) > t(i,k-1).`3940INPUT:4142- ``t`` -- A list of lists4344EXAMPLES::4546sage: CompositionTableau([[1],[2,2]])47[[1], [2, 2]]48sage: CompositionTableau([[1],[3,2],[4,4]])49[[1], [3, 2], [4, 4]]50sage: CompositionTableau([])51[]52"""53__metaclass__ = ClasscallMetaclass5455@staticmethod56def __classcall_private__(self, t):57r"""58This ensures that a composition tableau is only ever constructed as59an ``element_class`` call of an appropriate parent.6061TESTS::6263sage: t = CompositionTableau([[1],[2,2]])64sage: TestSuite(t).run()6566sage: t.parent()67Composition Tableaux68sage: t.category()69Category of elements of Composition Tableaux70"""71if isinstance(t, CompositionTableau):72return t73return CompositionTableaux_all().element_class(CompositionTableaux_all(), t)7475def __init__(self, parent, t):76r"""77Initialize a composition tableau.7879TESTS::8081sage: t = CompositionTableaux()([[1],[2,2]])82sage: s = CompositionTableaux(3)([[1],[2,2]])83sage: s==t84True85sage: t.parent()86Composition Tableaux87sage: s.parent()88Composition Tableaux of size 3 and maximum entry 389sage: r = CompositionTableaux()(s)90sage: r.parent()91Composition Tableaux92"""93if isinstance(t, CompositionTableau):94Element.__init__(self, parent)95CombinatorialObject.__init__(self, t._list)96return9798# CombinatorialObject verifies that t is a list99# We must verify t is a list of lists100if not all(isinstance(row, list) for row in t):101raise ValueError("A composition tableau must be a list of lists.")102103if not map(len,t) in Compositions():104raise ValueError("A composition tableau must be a list of non-empty lists.")105106# Verify rows weakly decrease from left to right107for row in t:108if any(row[i] < row[i+1] for i in range(len(row)-1)):109raise ValueError("Rows must weakly decrease from left to right.")110111# Verify leftmost column strictly increases from top to bottom112first_col = [row[0] for row in t if t!=[[]]]113if any(first_col[i] >= first_col[i+1] for i in range(len(t)-1)):114raise ValueError("Leftmost column must strictly increase from top to bottom.")115116# Verify triple condition117l = len(t)118m = max(map(len,t)+[0])119TT = [row+[0]*(m-len(row)) for row in t]120for i in range(l):121for j in range(i+1,l):122for k in range(1,m):123if TT[j][k] != 0 and TT[j][k] >= TT[i][k] and TT[j][k] <= TT[i][k-1]:124raise ValueError("Triple condition must be satisfied.")125126Element.__init__(self, parent)127CombinatorialObject.__init__(self, t)128129def _repr_diagram(self):130r"""131Return a string representation of ``self`` as an array.132133EXAMPLES::134135sage: t = CompositionTableau([[1],[3,2],[4,4]])136sage: print t._repr_diagram()13711383 21394 4140"""141return '\n'.join(["".join(map(lambda x: "%3s"%str(x) , row)) for row in self])142143def __call__(self, *cell):144r"""145Return the value in the corresponding cell of ``self``.146147EXAMPLES::148149sage: t = CompositionTableau([[1],[3,2],[4,4]])150sage: t(1,1)1512152sage: t(2,0)1534154sage: t(2,2)155Traceback (most recent call last):156...157IndexError: The cell (2,2) is not contained in [[1], [3, 2], [4, 4]]158"""159try:160i,j = cell161except ValueError:162i,j = cell[0]163164try:165return self[i][j]166except IndexError:167raise IndexError, "The cell (%d,%d) is not contained in %s"%(i,j,self)168169def pp(self):170r"""171Return a pretty print string of ``self``.172173EXAMPLES::174175sage: CompositionTableau([[1],[3,2],[4,4]]).pp()17611773 21784 4179"""180print self._repr_diagram()181182def size(self):183r"""184Return the number of boxes in ``self``.185186EXAMPLES::187188sage: CompositionTableau([[1],[3,2],[4,4]]).size()1895190"""191return sum([len(row) for row in self])192193def weight(self):194r"""195Return a composition where entry `i` is the number of times that `i` appears in196``self``.197198EXAMPLES::199200sage: CompositionTableau([[1],[3,2],[4,4]]).weight()201[1, 1, 1, 2, 0]202"""203w = {i:0 for i in range(1,self.size()+1)}204for row in self:205for i in row:206w[i] += 1207return Composition([w[i] for i in range(1,self.size()+1)])208209def descent_set(self):210r"""211Return the set of all `i` that do *not* have `i+1` appearing strictly212to the left of `i` in ``self``.213214EXAMPLES::215216sage: CompositionTableau([[1],[3,2],[4,4]]).descent_set()217[1, 3]218"""219cols = {}220for row in self:221for (col,i) in enumerate(row):222cols[i] = col223des_set = [i for i in cols if i+1 in cols and cols[i+1] >= cols[i]]224des_set.sort()225return des_set226227def descent_composition(self):228r"""229Return the composition corresponding to the set of all `i` that do230not have `i+1` appearing strictly to the left of `i` in ``self``.231232EXAMPLES::233234sage: CompositionTableau([[1],[3,2],[4,4]]).descent_composition()235[1, 2, 2]236"""237return Composition(from_subset=(self.descent_set(), self.size()))238239def shape_composition(self):240r"""241Return a Composition object which is the shape of ``self``.242243EXAMPLES::244245sage: CompositionTableau([[1,1],[3,2],[4,4,3]]).shape_composition()246[2, 2, 3]247sage: CompositionTableau([[2,1],[3],[4]]).shape_composition()248[2, 1, 1]249"""250return Composition([len(row) for row in self])251252def shape_partition(self):253r"""254Return a partition which is the shape of ``self`` sorted into weakly255decreasing order.256257EXAMPLES::258259sage: CompositionTableau([[1,1],[3,2],[4,4,3]]).shape_partition()260[3, 2, 2]261sage: CompositionTableau([[2,1],[3],[4]]).shape_partition()262[2, 1, 1]263"""264return Partition(sorted([len(row) for row in self], reverse=True))265266def is_standard(self):267r"""268Return ``True`` if ``self`` is a standard composition tableau and269``False`` otherwise.270271EXAMPLES::272273sage: CompositionTableau([[1,1],[3,2],[4,4,3]]).is_standard()274False275sage: CompositionTableau([[2,1],[3],[4]]).is_standard()276True277"""278entries = sum(self,[])279return sorted(entries) == range(1, self.size() + 1)280281class CompositionTableaux(UniqueRepresentation, Parent):282r"""283Composition tableaux.284285INPUT:286287Keyword arguments:288289- ``size`` -- the size of the composition tableaux290- ``shape`` -- the shape of the composition tableaux291- ``max_entry`` -- the maximum entry for the composition tableaux292293Positional arguments:294295- The first argument is interpreted as ``size`` or ``shape`` depending on296whether it is an integer or a composition.297298EXAMPLES::299300sage: CT = CompositionTableaux(3); CT301Composition Tableaux of size 3 and maximum entry 3302sage: list(CT)303[[[1], [2], [3]],304[[1], [2, 2]],305[[1], [3, 2]],306[[1], [3, 3]],307[[2], [3, 3]],308[[1, 1], [2]],309[[1, 1], [3]],310[[2, 1], [3]],311[[2, 2], [3]],312[[1, 1, 1]],313[[2, 1, 1]],314[[2, 2, 1]],315[[2, 2, 2]],316[[3, 1, 1]],317[[3, 2, 1]],318[[3, 2, 2]],319[[3, 3, 1]],320[[3, 3, 2]],321[[3, 3, 3]]]322323sage: CT = CompositionTableaux([1,2,1]); CT324Composition tableaux of shape [1, 2, 1] and maximun entry 4325sage: list(CT)326[[[1], [2, 2], [3]],327[[1], [2, 2], [4]],328[[1], [3, 2], [4]],329[[1], [3, 3], [4]],330[[2], [3, 3], [4]]]331332sage: CT = CompositionTableaux(shape=[1,2,1],max_entry=3); CT333Composition tableaux of shape [1, 2, 1] and maximun entry 3334sage: list(CT)335[[[1], [2, 2], [3]]]336337sage: CT = CompositionTableaux(2,max_entry=3); CT338Composition Tableaux of size 2 and maximum entry 3339sage: list(CT)340[[[1], [2]],341[[1], [3]],342[[2], [3]],343[[1, 1]],344[[2, 1]],345[[2, 2]],346[[3, 1]],347[[3, 2]],348[[3, 3]]]349350sage: CT = CompositionTableaux(0); CT351Composition Tableaux of size 0 and maximum entry 0352sage: list(CT)353[[]]354"""355@staticmethod356def __classcall_private__(cls, *args, **kwargs):357r"""358This is a factory class which returns the appropriate parent based on359arguments. See the documentation for :class:`CompositionTableaux` for360more information.361362TESTS::363364sage: CT = CompositionTableaux(3); CT365Composition Tableaux of size 3 and maximum entry 3366sage: CT = CompositionTableaux(size=3); CT367Composition Tableaux of size 3 and maximum entry 3368sage: CT = CompositionTableaux([1,2]); CT369Composition tableaux of shape [1, 2] and maximun entry 3370sage: CT = CompositionTableaux(shape=[1,2]); CT371Composition tableaux of shape [1, 2] and maximun entry 3372sage: CT = CompositionTableaux(shape=[]); CT373Composition tableaux of shape [] and maximun entry 0374sage: CT = CompositionTableaux(0); CT375Composition Tableaux of size 0 and maximum entry 0376sage: CT = CompositionTableaux(max_entry=3); CT377Composition tableaux with maximum entry 3378sage: CT = CompositionTableaux([1,2],max_entry=3); CT379Composition tableaux of shape [1, 2] and maximun entry 3380sage: CT = CompositionTableaux(size=2,shape=[1,2]); CT381Traceback (most recent call last):382...383ValueError: size and shape are different sizes384"""385# Process keyword arguments first386n = kwargs.get('n', None)387size = kwargs.get('size', n)388389comp = kwargs.get('comp', None)390shape = kwargs.get('shape', comp)391392max_entry = kwargs.get('max_entry', None)393394# Process positional arguments395if args:396# The first arg could be either a size or a shape397if isinstance(args[0], (int, Integer)):398if size is not None:399raise ValueError("size was specified more than once")400else:401size = args[0]402else:403if shape is not None:404raise ValueError("the shape was specified more than once")405shape = args[0]406407# Consistency checks408if size is not None:409if not isinstance(size, (int, Integer)):410raise ValueError("size must be an integer")411elif size < 0:412raise ValueError("size must be non-negative")413414if shape is not None:415# use in (and not isinstance) below so that lists can be used as416# shorthand417if not shape in Compositions():418raise ValueError("shape must be a composition")419if any(i == 0 for i in shape):420raise ValueError("shape must have non-zero parts")421shape = Composition(shape)422423if (size is not None) and (shape is not None):424if sum(shape) != size:425raise ValueError("size and shape are different sizes")426427if max_entry is not None:428if not isinstance(max_entry, (int, Integer)):429raise ValueError("max_entry must be an integer")430elif max_entry <= 0:431raise ValueError("max_entry must be positive")432433# Dispatch to appropriate class434if (shape is not None):435return CompositionTableaux_shape(shape, max_entry)436437if (size is not None):438return CompositionTableaux_size(size, max_entry)439440return CompositionTableaux_all(max_entry)441442def __init__(self, **kwds):443r"""444Initialize ``self``.445446TESTS::447448sage: CT = CompositionTableaux()449sage: TestSuite(CT).run()450"""451if kwds.has_key('max_entry'):452self.max_entry = kwds['max_entry']453kwds.pop('max_entry')454else:455self.max_entry = None456super(CompositionTableaux, self).__init__(**kwds)457458Element = CompositionTableau459460def _element_constructor_(self, t):461r"""462Construct an object from ``t`` as an element of ``self``, if463possible.464465INPUT:466467- ``t`` -- data which can be interpreted as a composition tableau468469OUTPUT:470471- The corresponding CompositionTableau object472473TESTS::474475sage: CT = CompositionTableaux(3)476sage: CT([[1],[2,2]]).parent() is CT477True478sage: CT([[1],[1,2]])479Traceback (most recent call last):480...481ValueError: [[1], [1, 2]] is not an element of Composition Tableaux of size 3 and maximum entry 3.482"""483if not t in self:484raise ValueError("%s is not an element of %s."%(t, self))485486return self.element_class(self, t)487488def __contains__(self, T):489r"""490Return ``True`` if ``T`` can be interpreted as491:class:`CompositionTableau`.492493TESTS::494495sage: [[1],[2,2]] in CompositionTableaux(3)496True497sage: [[1],[2,2]] in CompositionTableaux(shape=[1,2])498True499sage: CompositionTableau([[1],[2,2]]) in CompositionTableaux()500True501sage: [[1],[2,2],[2]] in CompositionTableaux()502False503"""504if isinstance(T, CompositionTableau):505return True506507# leftmost column of T strictly increases from top to bottom508first_col = [row[0] for row in T]509if any(first_col[i] >= first_col[i+1] for i in range(len(T)-1)):510return False511# rows of T weakly decrease from left to right512for row in T:513if any(row[i] < row[i+1] for i in range(len(row)-1)):514return False515# for 1 <= i < j <= len(comp), for 2 <= k <= m,516# T[j,k] \neq 0 and T[j,k] >= T[i,k] ==> T[j,k] > T[i,k-1]517l = len(T)518m = max(map(len,T)+[0])519TT = [row+[0]*(m-len(row)) for row in T]520for i in range(l):521for j in range(i+1,l):522for k in range(1,m):523if TT[j][k] != 0 and TT[j][k] >= TT[i][k] and TT[j][k] <= TT[i][k-1]:524return False525return True526527class CompositionTableaux_all(CompositionTableaux, DisjointUnionEnumeratedSets):528r"""529All composition tableaux.530"""531def __init__(self, max_entry=None):532r"""533Initialize ``self``.534535TESTS::536537sage: CT = CompositionTableaux()538sage: TestSuite(CT).run()539"""540self.max_entry = max_entry541CT_n = lambda n: CompositionTableaux_size(n, max_entry)542DisjointUnionEnumeratedSets.__init__(self,543Family(NonNegativeIntegers(), CT_n),544facade=True, keepkey = False)545546def _repr_(self):547r"""548TESTS::549550sage: CompositionTableaux(3)551Composition Tableaux of size 3 and maximum entry 3552553sage: CompositionTableaux()554Composition Tableaux555"""556if self.max_entry is not None:557return "Composition tableaux with maximum entry %s"%str(self.max_entry)558return "Composition Tableaux"559560def an_element(self):561r"""562Return a particular element of ``self``.563564EXAMPLES::565566sage: CT = CompositionTableaux()567sage: CT.an_element()568[[1, 1], [2]]569"""570return self.element_class(self, [[1, 1], [2]])571572class CompositionTableaux_size(CompositionTableaux):573r"""574Composition tableaux of a fixed size `n`.575576INPUT:577578- ``n`` -- a nonnegative integer.579- ``max_entry`` -- a nonnegative integer. This keyword argument defaults to ``n``.580581OUTUT:582583- The class of composition tableaux of size ``n``.584"""585def __init__(self, n, max_entry=None):586r"""587Initializes the class of composition tableaux of size ``n``.588589TESTS::590591sage: CT = CompositionTableaux(4)592sage: TestSuite(CT).run()593"""594if max_entry is None:595max_entry = n596super(CompositionTableaux_size, self).__init__(max_entry=max_entry,597category=FiniteEnumeratedSets())598self.size = n599600def __contains__(self,x):601r"""602TESTS::603604sage: [[1],[2,2]] in CompositionTableaux(3)605True606sage: [[1],[2,2]] in CompositionTableaux(4)607False608"""609return CompositionTableaux.__contains__(self, x) and sum(map(len,x)) == self.size610611def __iter__(self):612r"""613EXAMPLES::614615sage: [t for t in CompositionTableaux(3)]616[[[1], [2], [3]],617[[1], [2, 2]],618[[1], [3, 2]],619[[1], [3, 3]],620[[2], [3, 3]],621[[1, 1], [2]],622[[1, 1], [3]],623[[2, 1], [3]],624[[2, 2], [3]],625[[1, 1, 1]],626[[2, 1, 1]],627[[2, 2, 1]],628[[2, 2, 2]],629[[3, 1, 1]],630[[3, 2, 1]],631[[3, 2, 2]],632[[3, 3, 1]],633[[3, 3, 2]],634[[3, 3, 3]]]635636sage: CompositionTableaux(3)[0].parent() is CompositionTableaux(3)637True638"""639for comp in Compositions(self.size):640for T in CompositionTableaux_shape(comp,self.max_entry):641yield self.element_class(self, T)642643def _repr_(self):644r"""645TESTS::646647sage: CompositionTableaux(3)648Composition Tableaux of size 3 and maximum entry 3649"""650return "Composition Tableaux of size %s and maximum entry %s"%(str(self.size), str(self.max_entry))651652def _an_element_(self):653r"""654Return a particular element of ``self``.655656EXAMPLES::657658sage: CT = CompositionTableaux(4)659sage: CT.an_element()660[[1, 1, 1], [2]]661sage: CompositionTableaux(0).an_element()662[]663sage: CompositionTableaux(1).an_element()664[[1]]665"""666if self.size == 0:667return self.element_class(self, [])668if self.size == 1:669return self.element_class(self,[[1]])670671return self.element_class(self, [[1]*(self.size-1),[2]])672673class CompositionTableaux_shape(CompositionTableaux):674r"""675Composition tableaux of a fixed shape ``comp`` with a given max entry.676677INPUT:678679- ``comp`` -- a composition.680- ``max_entry`` -- a nonnegative integer. This keyword argument defaults681to the size of ``comp``.682"""683def __init__(self, comp, max_entry=None):684"""685Initialize ``sefl``.686687TESTS::688689sage: CT = CompositionTableaux([1,2])690sage: TestSuite(CT).run()691692sage: CT = CompositionTableaux([1,2], max_entry=4)693sage: TestSuite(CT).run()694"""695if max_entry is None:696max_entry = sum(comp)697super(CompositionTableaux_shape, self).__init__(max_entry = max_entry,698category = FiniteEnumeratedSets())699self.shape = comp700701def __iter__(self):702r"""703An iterator for composition tableaux of a given shape.704705EXAMPLES::706707sage: [t for t in CompositionTableaux([1,2])]708[[[1], [2, 2]], [[1], [3, 2]], [[1], [3, 3]], [[2], [3, 3]]]709sage: [t for t in CompositionTableaux([1,2],max_entry=4)]710[[[1], [2, 2]],711[[1], [3, 2]],712[[1], [3, 3]],713[[1], [4, 2]],714[[1], [4, 3]],715[[1], [4, 4]],716[[2], [3, 3]],717[[2], [4, 3]],718[[2], [4, 4]],719[[3], [4, 4]]]720"""721if sum(self.shape) == 0:722yield CompositionTableau([])723else:724for z in CompositionTableauxBacktracker(self.shape, self.max_entry):725yield CompositionTableau(z)726727def __contains__(self, x):728r"""729TESTS::730731sage: [[2],[4,3]] in CompositionTableaux([1,2])732True733sage: [[2],[3,2]] in CompositionTableaux([1,2])734False735"""736return CompositionTableaux.__contains__(self, x) and map(len, x) == self.shape737738def _repr_(self):739r"""740TESTS::741742sage: CompositionTableaux([1,2,1])743Composition tableaux of shape [1, 2, 1] and maximun entry 4744sage: CompositionTableaux([1,2,1],max_entry=3)745Composition tableaux of shape [1, 2, 1] and maximun entry 3746"""747return "Composition tableaux of shape %s and maximun entry %s"%(str(self.shape), str(self.max_entry))748749def an_element(self):750r"""751Return a particular element of :class:`CompositionTableaux_shape`.752753EXAMPLES::754755sage: CT = CompositionTableaux([1,2,1])756sage: CT.an_element()757[[1], [2, 2], [3]]758"""759if self.shape == []:760return self.element_class(self, [])761t = [[i]*len for (i,len) in enumerate(self.shape,start=1)]762return self.element_class(self, t)763764class CompositionTableauxBacktracker(GenericBacktracker):765r"""766A backtracker class for generating sets of composition tableaux.767"""768def __init__(self, shape, max_entry=None):769"""770EXAMPLES::771772sage: from sage.combinat.composition_tableau import CompositionTableauxBacktracker773sage: n = CompositionTableauxBacktracker([1,3,2])774sage: n._ending_position775(2, 1)776sage: n._initial_state777(0, 0)778"""779self._shape = shape780self._n = sum(shape)781self._initial_data = [ [None]*s for s in shape ]782if max_entry==None:783max_entry=sum(shape)784self.max_entry=max_entry785786# The ending position will be at the lowest box which is farthest right787ending_row = len(shape)-1788ending_col = shape[-1]-1789self._ending_position = (ending_row, ending_col)790791# Get the highest box that is farthest left792starting_row = 0793starting_col = 0794795GenericBacktracker.__init__(self, self._initial_data, (starting_row, starting_col))796797def _rec(self, obj, state):798r"""799EXAMPLES::800801sage: from sage.combinat.composition_tableau import CompositionTableauxBacktracker802sage: n = CompositionTableauxBacktracker([1,3,2])803sage: obj = [ [None], [None, None, None], [None, None] ]804sage: list(n._rec(obj, n._initial_state))805[([[1], [None, None, None], [None, None]], (1, 0), False),806([[2], [None, None, None], [None, None]], (1, 0), False),807([[3], [None, None, None], [None, None]], (1, 0), False),808([[4], [None, None, None], [None, None]], (1, 0), False),809([[5], [None, None, None], [None, None]], (1, 0), False),810([[6], [None, None, None], [None, None]], (1, 0), False)]811"""812#Append zeros to a copy of obj813obj_copy = copy.deepcopy(obj)814for a in range(len(obj_copy)):815for b in range(len(max(obj_copy))-len(obj_copy[a])):816obj_copy[a].append(0)817818#We need to set the i,j^th entry.819i, j = state820821#Get the next state822new_state = self.get_next_pos(i, j)823yld = True if new_state is None else False824825for k in range(1,self.max_entry +1):826#We check to make sure that k does not violate the rule weak decrease in rows827if j!=0 and obj[i][j-1] < k:828continue829830#We check to make sure that k does not violate strict increase in first column831if j == 0 and i != 0 and k <= obj[i-1][j]:832continue833834#We check to make sure that k does not violate the Triple Rule835if j != 0 and i != 0 and any(k == obj_copy[m][j] for m in range(i)):836continue837if j != 0 and i != 0 and any(obj_copy[m][j] < k and k <= obj_copy[m][j-1] for m in range(i)):838continue839840#Fill in the in the i,j box with k841obj[i][j] = k842obj_copy[i][j] = k843844#Yield the object845yield copy.deepcopy(obj), new_state, yld846847def get_next_pos(self, ii, jj):848r"""849EXAMPLES::850851sage: from sage.combinat.composition_tableau import CompositionTableauxBacktracker852sage: T = CompositionTableau([[2,1],[5,4,3,2],[6],[7,7,6]])853sage: n = CompositionTableauxBacktracker(T.shape_composition())854sage: n.get_next_pos(1,1)855(1, 2)856"""857if (ii, jj) == self._ending_position:858return None859860for j in range(jj+1, self._shape[ii]):861if self._shape[ii] >= j:862return ii, j863864return ii+1, 0865866867868