Ticket #13838: trac_13838-virtual_kleber_alg-ts.patch

File trac_13838-virtual_kleber_alg-ts.patch, 59.2 KB (added by tscrim, 9 years ago)

New version

  • sage/combinat/rigged_configurations/all.py

    # HG changeset patch
    # User Travis Scrimshaw <tscrim@ucdavis.edur>
    # Date 1377192427 25200
    # Node ID 0062cf308415e4b9a788f61f98c061ea0492485b
    # Parent eed1dffa9950bdd8f92424f6de07e6250e88add3
    Trac 13838 - Implemented virtual Kleber tree
    
    diff --git a/sage/combinat/rigged_configurations/all.py b/sage/combinat/rigged_configurations/all.py
    a b from rigged_configurations import Rigged 
    33from tensor_product_kr_tableaux import HighestWeightTensorProductOfKirillovReshetikhinTableaux
    44from tensor_product_kr_tableaux import TensorProductOfKirillovReshetikhinTableaux
    55from kr_tableaux import KirillovReshetikhinTableaux
    6 from kleber_tree import KleberTree
     6
  • sage/combinat/rigged_configurations/kleber_tree.py

    diff --git a/sage/combinat/rigged_configurations/kleber_tree.py b/sage/combinat/rigged_configurations/kleber_tree.py
    a b  
    11r"""
    2 Kleber tree
     2Kleber Trees
    33
    44A Kleber tree is a tree of weights generated by Kleber's algorithm
    55[Kleber1]_. The nodes correspond to the weights in the positive Weyl chamber
    the coefficients of the roots of the dif 
    99AUTHORS:
    1010
    1111- Travis Scrimshaw (2011-05-03): Initial version
    12 
    13 REFERENCES:
    14 
    15     .. [Kleber1] Michael Kleber.
    16         Combinatorial structure of finite dimensional representations of Yangians:
    17         the simply-laced case.
    18         Internat. Math. Res. Notices 1997. no. 4. 187-201.
    19 
    20     .. [Kleber2] Michael Kleber.
    21         Finite dimensional representations of quantum affine algebras.
    22         Ph.D. dissertation at University of California Berkeley. 1998.
    23         math.QA/9809087.
    24 
    25 .. TODO:: Output the tree as a graph using the graph code
     12- Travis Scrimshaw (2013-02-13): Added support for virtual trees and improved
     13  `\LaTeX` output
    2614
    2715EXAMPLES::
    2816
    29     sage: KleberTree(['A', 3], [[3,2], [2,1], [1,1], [1,1]])
    30     Kleber tree of Cartan type ['A', 3] and root weight [2, 1, 2]
    31     sage: KleberTree(['D', 4], [[2,2]])
    32     Kleber tree of Cartan type ['D', 4] and root weight [0, 2, 0, 0]
     17    sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
     18    sage: KleberTree(['A', 3, 1], [[3,2], [2,1], [1,1], [1,1]])
     19    Kleber tree of Cartan type ['A', 3, 1] and B = ((3, 2), (2, 1), (1, 1), (1, 1))
     20    sage: KleberTree(['D', 4, 1], [[2,2]])
     21    Kleber tree of Cartan type ['D', 4, 1] and B = ((2, 2),)
    3322
    3423TESTS::
    3524
    36     sage: KT = KleberTree(['A', 3], [[3,2], [2,1], [1,1], [1,1]])
     25    sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
     26    sage: KT = KleberTree(['A', 3, 1], [[3,2], [2,1], [1,1], [1,1]])
    3727    sage: for x in set(KT.list()): x
    38     ...
    3928    Kleber tree node with weight [1, 0, 3] and upwards edge root [1, 1, 0]
    4029    Kleber tree node with weight [0, 2, 2] and upwards edge root [1, 0, 0]
    4130    Kleber tree node with weight [2, 1, 2] and upwards edge root [0, 0, 0]
    TESTS:: 
    4736    Kleber tree node with weight [1, 1, 1] and upwards edge root [1, 1, 1]
    4837    Kleber tree node with weight [0, 0, 2] and upwards edge root [2, 2, 1]
    4938
    50     sage: KT = KleberTree(['A', 7], [[3,2], [2,1], [1,1]])
     39    sage: KT = KleberTree(['A', 7, 1], [[3,2], [2,1], [1,1]])
    5140    sage: KT
    52     Kleber tree of Cartan type ['A', 7] and root weight [1, 1, 2, 0, 0, 0, 0]
     41    Kleber tree of Cartan type ['A', 7, 1] and B = ((3, 2), (2, 1), (1, 1))
    5342    sage: for x in set(KT.list()): x
    54     ...
    5543    Kleber tree node with weight [1, 0, 1, 0, 1, 0, 0] and upwards edge root [1, 2, 2, 1, 0, 0, 0]
    5644    Kleber tree node with weight [0, 0, 1, 0, 0, 1, 0] and upwards edge root [2, 3, 3, 2, 1, 0, 0]
    5745    Kleber tree node with weight [1, 1, 2, 0, 0, 0, 0] and upwards edge root [0, 0, 0, 0, 0, 0, 0]
    TESTS:: 
    6048    Kleber tree node with weight [0, 0, 3, 0, 0, 0, 0] and upwards edge root [1, 1, 0, 0, 0, 0, 0]
    6149    Kleber tree node with weight [0, 0, 0, 1, 1, 0, 0] and upwards edge root [1, 1, 1, 0, 0, 0, 0]
    6250    Kleber tree node with weight [0, 1, 1, 1, 0, 0, 0] and upwards edge root [1, 1, 1, 0, 0, 0, 0]
    63 
    6451"""
    6552
    6653#*****************************************************************************
    TESTS:: 
    7966#*****************************************************************************
    8067
    8168from sage.misc.lazy_attribute import lazy_attribute
     69from sage.misc.cachefunc import cached_method
    8270from sage.misc.latex import latex
     71from sage.rings.arith import binomial
    8372from sage.rings.integer import Integer
    8473
    8574from sage.structure.parent import Parent
    from sage.combinat.cartesian_product imp 
    9382from sage.graphs.digraph import DiGraph
    9483from sage.graphs.dot2tex_utils import have_dot2tex
    9584
     85######################################
     86# Latex method for viewing the trees #
     87######################################
     88
     89def _draw_tree(tree_node, node_label=True, style_point=None, style_node='fill=white', style_line=None,
     90               hspace=2.5, vspace=-2.5, start=[0.,0.], rpos=[0.,0.], node_id=0, node_prefix='T',
     91               edge_labels=True, use_vector_notation=False):
     92    r"""
     93    Return the tikz latex for drawing the Kleber tree.
     94
     95    AUTHORS:
     96
     97    - Viviane Pons (2013-02-13): Initial version
     98    - Travis Scrimshaw (2013-03-02): Modified to work with Kleber tree output
     99
     100    .. WARNING::
     101
     102        Internal latex function.
     103
     104    EXAMPLES::
     105
     106        sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
     107        sage: KT = KleberTree(['A',3,1], [[3,2],[1,1]])
     108        sage: latex(KT)
     109        \begin{tikzpicture}
     110        \node[fill=white] (T0) at (0.000, 0.000){$V_{\omega_{1}+2\omega_{3}}$};
     111        \node (T00) at (0.000, -2.500){$V_{\omega_{3}}$};
     112        \draw (T0) to node[sloped,above]{\tiny $\alpha_{1} + \alpha_{2} + \alpha_{3}$} (T00);
     113        \end{tikzpicture}
     114    """
     115    draw_point = lambda point: '(%.3f, %.3f)'%(point[0],point[1])
     116    if len(tree_node.children) == 0:
     117        r = ''
     118        node_name = node_prefix + str(node_id)
     119        r = "\\node (%s) at %s"%(node_name, draw_point(start))
     120        if(node_label):
     121            r += "{$%s$};\n"%tree_node._latex_()
     122        else:
     123            r += "{};\n"
     124        rpos[0] = start[0]
     125        rpos[1] = start[1]
     126        start[0] += hspace
     127        return r
     128
     129    node_name = node_prefix + str(node_id)
     130    if style_line is None:
     131        style_line_str = ''
     132    else:
     133        style_line_str = "[%s]"%style_line
     134    if node_label:
     135        node_place_str = ''
     136    else:
     137        node_place_str = ".center"
     138
     139    nb_children = len(tree_node.children)
     140    half = int(nb_children/2)
     141    children_str = ''
     142    pos = [start[0],start[1]]
     143    start[1] += vspace
     144    lines_str = ''
     145
     146    # Getting children string
     147    for i in xrange(nb_children):
     148        if i == half and nb_children % 2 == 0:
     149            pos[0] = start[0]
     150            start[0] += hspace
     151        if i == half+1 and nb_children % 2 == 1:
     152            pos[0] = rpos[0]
     153        child = tree_node.children[i]
     154        children_str += _draw_tree(child, node_label=node_label, style_node=style_node, style_point=style_point, style_line=style_line, hspace=hspace, vspace=vspace, start=start, rpos=rpos, node_id=i, node_prefix=node_name, edge_labels=edge_labels, use_vector_notation=use_vector_notation)
     155        if edge_labels:
     156            if use_vector_notation:
     157                edge_str = latex(child.up_root.to_vector())
     158            else:
     159                edge_str = latex(child.up_root)
     160            lines_str += "\\draw%s (%s%s) to node[sloped,above]{\\tiny $%s$} (%s%s%s);\n"%(style_line_str, node_name, node_place_str, edge_str, node_name, i, node_place_str)
     161        else:
     162            lines_str += "\\draw%s (%s%s) -- (%s%s%s);\n"%(style_line_str, node_name, node_place_str, node_name, i, node_place_str)
     163
     164    #drawing root
     165    if style_node is None:
     166        style_node = ''
     167    else:
     168        style_node = "[%s]"%style_node
     169    if style_point is None:
     170        style_point = ''
     171    else:
     172        style_point = "[%s]"%style_point
     173    start[1] -= vspace
     174    rpos[0] = pos[0]
     175    rpos[1] = pos[1]
     176    point_str = ''
     177    node_str = "\\node%s (%s) at %s"%(style_node, node_name, draw_point(pos))
     178    if(node_label):
     179        node_str += "{$%s$};\n"%tree_node._latex_()
     180    else:
     181        node_str += "{};\n"
     182        point_str = "\\draw%s (%s) circle;\n"%(style_point, node_name)
     183
     184    res = node_str
     185    res += children_str
     186    res += lines_str
     187    res += point_str
     188    return res
     189
     190#####################
     191# Kleber tree nodes #
     192#####################
     193
    96194class KleberTreeNode(Element):
    97195    r"""
    98196    A node in the Kleber tree.
    99197
    100198    This class is meant to be used internally by the Kleber tree class and
    101199    should not be created directly by the user.
    102    
     200
    103201    For more on the Kleber tree and the nodes, see :class:`KleberTree`.
     202
     203    The dominating root is the ``up_root`` which is the difference
     204    between the parent node's weight and this node's weight.
     205
     206    INPUT:
     207
     208    - ``parent_obj``    -- The parent object of this element
     209    - ``node_weight``   -- The weight of this node
     210    - ``dominant_root`` -- The dominating root
     211    - ``parent_node``   -- (default:None) The parent node of this node
    104212    """
    105 
    106213    def __init__(self, parent_obj, node_weight, dominant_root, parent_node=None):
    107214        r"""
    108215        Initialize the tree node.
    109216
    110         The dominating root is the up_root which is the difference between the
    111         parent node's weight and this node's weight.
    112 
    113         INPUT:
    114 
    115         - ``parent_obj``    -- The parent object of this element
    116         - ``node_weight``   -- The weight of this node
    117         - ``dominant_root`` -- The dominating root
    118         - ``parent_node``   -- (default:None) The parent node of this node
    119 
    120217        TESTS::
    121218
     219            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
    122220            sage: RS = RootSystem(['A', 2])
    123221            sage: WS = RS.weight_space()
    124222            sage: R = RS.root_space()
    125             sage: KT = KleberTree(['A', 2], [[1,1]])
     223            sage: KT = KleberTree(['A', 2, 1], [[1,1]])
    126224            sage: parent = KT(WS.sum_of_terms([(1,5), (2,2)]), R.zero())
    127225            sage: parent
    128226            Kleber tree node with weight [5, 2] and upwards edge root [0, 0]
    class KleberTreeNode(Element): 
    139237        self.weight = node_weight
    140238        self.up_root = dominant_root
    141239        Element.__init__(self, parent_obj)
    142    
     240
    143241    @lazy_attribute
    144242    def depth(self):
    145243        """
    146244        Return the depth of this node in the tree.
    147        
     245
    148246        EXAMPLES::
    149        
     247
     248            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
    150249            sage: RS = RootSystem(['A', 2])
    151250            sage: WS = RS.weight_space()
    152251            sage: R = RS.root_space()
    153             sage: KT = KleberTree(['A', 2], [[1,1]])
     252            sage: KT = KleberTree(['A', 2, 1], [[1,1]])
    154253            sage: n = KT(WS.sum_of_terms([(1,5), (2,2)]), R.zero())
    155254            sage: n.depth
    156             1
     255            0
    157256            sage: n2 = KT(WS.sum_of_terms([(1,5), (2,2)]), R.zero(), n)
    158257            sage: n2.depth
    159             2
     258            1
    160259        """
    161         depth = 0
     260        depth = -1 # Offset
    162261        cur = self
    163262        while cur is not None:
    164263            depth += 1
    165264            cur = cur.parent_node
    166        
     265
    167266        return depth
    168        
     267
     268    @cached_method
     269    def multiplicity(self):
     270        r"""
     271        Return the multiplicity of ``self``.
     272
     273        The multiplicity of a node `x` of depth `d` weight `\lambda` in a
     274        simply-laced Kleber tree is equal to:
     275
     276        .. MATH::
     277
     278            \prod_{a \in \overline{I}} \prod_{i > 0}
     279            \binom{p_i^{(a)} + m_i^{(a)}}{p_i^{(a)}}
     280
     281        Recall that
     282
     283        .. MATH::
     284
     285            m_i^{(a)} = \left( \lambda^{(i-1)} - 2 \lambda^{(i)} +
     286            \lambda^{(i+1)} \mid \overline{\Lambda}_a \right)
     287
     288            p_i^{(a)} = -\sum_{j > i} L_j^{(a)} + \left( \alpha_a \mid
     289            \lambda^{(i)} \right)
     290
     291        where `\lambda^{(i)}` is the weight node at depth `i` in the path
     292        to `x` from the root and we set `\lambda^{(j)} = \lambda` for all
     293        `j \geq d`.
     294
     295        Note that `m_i^{(a)} = 0` for all `i > d`.
     296
     297        EXAMPLES::
     298
     299            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
     300            sage: KT = KleberTree(['A',3,1], [[3,2],[2,1],[1,1],[1,1]])
     301            sage: for x in KT: x, x.multiplicity()
     302            (Kleber tree node with weight [2, 1, 2] and upwards edge root [0, 0, 0], 1)
     303            (Kleber tree node with weight [0, 2, 2] and upwards edge root [1, 0, 0], 1)
     304            (Kleber tree node with weight [1, 0, 3] and upwards edge root [1, 1, 0], 2)
     305            (Kleber tree node with weight [1, 1, 1] and upwards edge root [1, 1, 1], 4)
     306            (Kleber tree node with weight [0, 0, 2] and upwards edge root [2, 2, 1], 2)
     307            (Kleber tree node with weight [3, 0, 1] and upwards edge root [0, 1, 1], 1)
     308            (Kleber tree node with weight [2, 0, 0] and upwards edge root [0, 1, 1], 2)
     309            (Kleber tree node with weight [0, 0, 2] and upwards edge root [1, 1, 0], 1)
     310            (Kleber tree node with weight [0, 1, 0] and upwards edge root [1, 1, 1], 2)
     311            (Kleber tree node with weight [0, 1, 0] and upwards edge root [0, 0, 1], 1)
     312        """
     313        # The multiplicity corresponding to the root is always 1
     314        if self.parent_node is None:
     315            return Integer(1)
     316
     317        mult = Integer(1)
     318        for a, m in enumerate(self.up_root.to_vector()):
     319            if m == 0:
     320                continue
     321            p = self.weight[a+1] #+1 for indexing
     322            old_p = p
     323            for dim in self.parent().B:
     324                if dim[0] == a + 1 and dim[1] > self.depth:
     325                    p -= 1 #min(dim[1], self.depth)
     326            mult *= binomial(m + p, m)
     327
     328        prev_up_root = self.up_root
     329        cur = self.parent_node
     330        while cur.parent_node is not None:
     331            root_diff = (cur.up_root - prev_up_root).to_vector()
     332            for a, m in enumerate(root_diff):
     333                if m == 0:
     334                    continue
     335                p = cur.weight[a+1] #+1 for indexing
     336                old_p = p
     337                for dim in self.parent().B:
     338                    if dim[0] == a + 1 and dim[1] > cur.depth:
     339                        p -= 1
     340                mult *= binomial(m + p, m)
     341            prev_up_root = cur.up_root
     342            cur = cur.parent_node
     343
     344        return mult
     345
    169346    def __cmp__(self, rhs):
    170347        r"""
    171348        Check whether two nodes are equal.
    172        
     349
    173350        TESTS::
    174351
     352            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
    175353            sage: RS = RootSystem(['A', 2])
    176354            sage: WS = RS.weight_space()
    177355            sage: R = RS.root_space()
    178             sage: KT = KleberTree(['A', 2], [[1,1]])
     356            sage: KT = KleberTree(['A', 2, 1], [[1,1]])
    179357            sage: n = KT(WS.sum_of_terms([(1,5), (2,2)]), R.zero())
    180358            sage: n2 = KT(WS.sum_of_terms([(1,5), (2,2)]), R.zero(), n)
    181359            sage: cmp(n2, n)
    class KleberTreeNode(Element): 
    203381
    204382        EXAMPLES::
    205383
     384            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
    206385            sage: RS = RootSystem(['A', 3])
    207386            sage: WS = RS.weight_space()
    208387            sage: R = RS.root_space()
    209             sage: KT = KleberTree(['A', 2], [[1,1]])
    210             sage: node = sage.combinat.rigged_configurations.kleber_tree.KleberTreeNode(KT, WS.sum_of_terms([(1,2), (2,1), (3,1)]), R.sum_of_terms([(1,3), (3,3)])); node # indirect doctest
     388            sage: KT = KleberTree(['A', 2, 1], [[1,1]])
     389            sage: node = KT(WS.sum_of_terms([(1,2), (2,1), (3,1)]), R.sum_of_terms([(1,3), (3,3)])); node
    211390            Kleber tree node with weight [2, 1, 1] and upwards edge root [3, 0, 3]
     391
     392        With virtual nodes::
     393
     394            sage: from sage.combinat.rigged_configurations.kleber_tree import VirtualKleberTree
     395            sage: KT = VirtualKleberTree(['A',6,2], [[2,2]])
     396            sage: KT.root
     397            Kleber tree node with weight [0, 2, 0, 2, 0] and upwards edge root [0, 0, 0, 0, 0]
    212398        """
    213         ret_str = "Kleber tree node with weight " + repr(list(self.weight.to_vector()))
    214         ret_str += " and upwards edge root " + repr(list(self.up_root.to_vector()))
    215         return ret_str
     399        return "Kleber tree node with weight %s and upwards edge root %s"%(
     400            list(self.weight.to_vector()), list(self.up_root.to_vector()) )
    216401
    217402    def _latex_(self):
    218403        r"""
    class KleberTreeNode(Element): 
    220405
    221406        TESTS::
    222407
     408            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
    223409            sage: RS = RootSystem(['A', 3])
    224410            sage: WS = RS.weight_space()
    225411            sage: R = RS.root_space()
    226             sage: KT = KleberTree(['A', 3], [[3,2], [1,1]])
    227             sage: node = sage.combinat.rigged_configurations.kleber_tree.KleberTreeNode(KT, WS.sum_of_terms([(1,4), (3,1)]), R.zero())
    228             sage: latex(node) # indirect doctest
     412            sage: KT = KleberTree(['A', 3, 1], [[3,2], [1,1]])
     413            sage: node = KT(WS.sum_of_terms([(1,4), (3,1)]), R.zero())
     414            sage: latex(node)
    229415            V_{4\omega_{1}+\omega_{3}}
    230             sage: node = sage.combinat.rigged_configurations.kleber_tree.KleberTreeNode(KT, WS.zero(), R.zero())
    231             sage: latex(node) # indirect doctest
     416            sage: node = KT(WS.zero(), R.zero())
     417            sage: latex(node)
    232418            V_{0}
    233             sage: node = sage.combinat.rigged_configurations.kleber_tree.KleberTreeNode(KT, WS.sum_of_terms([(1,2)]), R.zero())
    234             sage: latex(node) # indirect doctest
     419            sage: node = KT(WS.sum_of_terms([(1,2)]), R.zero())
     420            sage: latex(node)
    235421            V_{2\omega_{1}}
     422
     423        With virtual nodes::
     424
     425            sage: from sage.combinat.rigged_configurations.kleber_tree import VirtualKleberTree
     426            sage: KT = VirtualKleberTree(['C',3,1], [[2,2]])
     427            sage: latex(KT.root)
     428            [V_{2\omega_{2}+2\omega_{4}}]
     429            sage: KT = VirtualKleberTree(['A',6,2], [[2,2]])
     430            sage: latex(KT.root)
     431            [V_{2\omega_{2}+2\omega_{4}}]
    236432        """
    237         retStr = "V_{"
     433        ret_str = "V_{"
     434        if self.multiplicity() != 1:
     435            ret_str = repr(self.multiplicity()) + ret_str
    238436        for pair in self.weight:
    239437            if pair[1] > 1:
    240                 retStr += repr(pair[1]) + "\omega_{" + repr(pair[0]) + "}+"
     438                ret_str += repr(pair[1]) + "\omega_{" + repr(pair[0]) + "}+"
    241439            elif pair[1] == 1:
    242                 retStr += "\omega_{" + repr(pair[0]) + "}+"
     440                ret_str += "\omega_{" + repr(pair[0]) + "}+"
    243441
    244         if retStr[-1] == '{':
    245             retStr += "0}"
     442        if ret_str[-1] == '{':
     443            ret_str += "0}"
    246444        else:
    247             retStr = retStr[:-1] + "}"
    248         return retStr
     445            ret_str = ret_str[:-1] + "}"
     446
     447        ct = self.parent()._cartan_type
     448        if ct.type() == 'BC' or ct.dual().type() == 'BC':
     449            return "[" + ret_str + "]"
     450        elif not ct.is_simply_laced():
     451            s_factors = self.parent()._folded_ct.scaling_factors()
     452            gamma = max(s_factors)
     453            # Subtract 1 for indexing
     454            if gamma > 1:
     455                L = [self.parent()._folded_ct.folding_orbit()[a][0] for a in
     456                     range(1, len(s_factors)) if s_factors[a] == gamma]
     457            else:
     458                L = []
     459
     460            if self.depth % gamma == 0 or all(self.up_root[a] == 0 for a in L):
     461                return "[" + ret_str + "]"
     462        return ret_str
     463
     464#######################
     465# Kleber tree classes #
     466#######################
    249467
    250468class KleberTree(Parent, UniqueRepresentation):
    251469    r"""
    252470    The tree that is generated by Kleber's algorithm.
    253    
     471
    254472    A Kleber tree is a tree of weights generated by Kleber's algorithm
    255473    [Kleber1]_. It is used to generate the set of all admissible rigged
    256     configurations for the simply-laced types `A_n`, `D_n`, `E_6`, `E_7`,
    257     and `E_8`.
    258    
     474    configurations for the simply-laced affine types `A_n^{(1)}`,
     475    `D_n^{(1)}`, `E_6^{(1)}`, `E_7^{(1)}`, and `E_8^{(1)}`.
     476
     477    .. SEEALSO::
     478
     479        There is a modified version for non-simply-laced affine types at
     480        :class:`VirtualKleberTree`.
     481
    259482    The nodes correspond to the weights in the positive Weyl chamber obtained
    260483    by subtracting a (non-zero) positive root. The edges are labeled by the
    261484    coefficients of the roots, and `X` is a child of `Y` if `Y` is the root
    262485    else if the edge label of `Y` to its parent `Z` is greater (in every
    263486    component) than the label from `X` to `Y`.
    264487
    265     For a Kleber tree, one needs to specify a Cartan type and a sequence of
    266     tuples `[r,s]`, where `s` is any positive integer and `r` is a node in
    267     the Dynkin diagram. Each `[r,s]` can be viewed as a rectangle of width
    268     `s` and height `r`.
     488    For a Kleber tree, one needs to specify an affine (simply-laced)
     489    Cartan type and a sequence of pairs `(r,s)`, where `s` is any positive
     490    integer and `r` is a node in the Dynkin diagram. Each `(r,s)` can be
     491    viewed as a rectangle of width `s` and height `r`.
    269492
    270     EXAMPLES::
     493    INPUT:
    271494
    272         sage: KT = KleberTree(['E', 6], [[4, 2]])  # long time (9s on sage.math, 2012)
     495    - ``cartan_type`` -- an affine simply-laced Cartan type
     496
     497    - ``B`` -- a list of dimensions of rectangles by `[r, c]`
     498      where `r` is the number of rows and `c` is the number of columns
     499
     500    REFERENCES:
     501
     502    .. [Kleber1] Michael Kleber.
     503       *Combinatorial structure of finite dimensional representations of
     504       Yangians: the simply-laced case*.
     505       Internat. Math. Res. Notices. (1997) no. 4. 187-201.
     506
     507    .. [Kleber2] Michael Kleber.
     508       *Finite dimensional representations of quantum affine algebras*.
     509       Ph.D. dissertation at University of California Berkeley. (1998).
     510       :arxiv:`math.QA/9809087`.
     511
     512    EXAMPLES:
     513
     514    Simply-laced example::
     515
     516        sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
     517        sage: KT = KleberTree(['A', 3, 1], [[3,2], [1,1]])
     518        sage: KT.list()
     519        [Kleber tree node with weight [1, 0, 2] and upwards edge root [0, 0, 0],
     520         Kleber tree node with weight [0, 0, 1] and upwards edge root [1, 1, 1]]
     521        sage: KT = KleberTree(['A', 3, 1], [[3,2], [2,1], [1,1], [1,1]])
     522        sage: KT.cardinality()
     523        10
     524        sage: KT = KleberTree(['D', 4, 1], [[2,2]])
     525        sage: KT.cardinality()
     526        3
     527        sage: KT = KleberTree(['D', 4, 1], [[4,5]])
     528        sage: KT.cardinality()
     529        1
     530
     531    From [Kleber2]_::
     532
     533        sage: KT = KleberTree(['E', 6, 1], [[4, 2]])  # long time (9s on sage.math, 2012)
    273534        sage: KT.cardinality()  # long time
    274535        12
    275         sage: KT = KleberTree(['A', 3], [[3,2], [1,1]])  # long time
    276         sage: KT.list()  # long time
    277         [Kleber tree node with weight [1, 0, 2] and upwards edge root [0, 0, 0],
    278         Kleber tree node with weight [0, 0, 1] and upwards edge root [1, 1, 1]]
    279536    """
    280 
    281537    @staticmethod
    282     def __classcall_private__(cls, cartan_type, B):
     538    def __classcall_private__(cls, cartan_type, B, classical=None):
    283539        """
    284540        Normalize the input arguments to ensure unique representation.
    285541
    286542        EXAMPLES::
    287543
    288             sage: KT1 = KleberTree(CartanType(['A',3]), [[2,2]])
    289             sage: KT2 = KleberTree(['A',3], [(2,2)])
    290             sage: KT3 = KleberTree(['A',3], ((2,2),))
     544            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
     545            sage: KT1 = KleberTree(CartanType(['A',3,1]), [[2,2]])
     546            sage: KT2 = KleberTree(['A',3,1], [(2,2)])
     547            sage: KT3 = KleberTree(['A',3,1], ((2,2),))
    291548            sage: KT2 is KT1, KT3 is KT1
    292549            (True, True)
    293550        """
    294551        cartan_type = CartanType(cartan_type)
     552        if not cartan_type.is_affine():
     553            raise ValueError("The Cartan type must be affine")
     554
     555        if not cartan_type.classical().is_simply_laced():
     556            raise ValueError("use VirtualKleberTree for non-simply-laced types")
     557
    295558        # Standardize B input into a tuple of tuples
    296         assert B is not None
    297         B = tuple(tuple(dim) for dim in B)
    298         return super(KleberTree, cls).__classcall__(cls, cartan_type, B)
     559        B = tuple(map(tuple, B))
    299560
    300     def __init__(self, cartan_type, B):
     561        if classical is None:
     562            classical = cartan_type.classical()
     563        else:
     564            classical = CartanType(classical)
     565        return super(KleberTree, cls).__classcall__(cls, cartan_type, B, classical)
     566
     567    def __init__(self, cartan_type, B, classical_ct):
    301568        r"""
    302569        Construct a Kleber tree.
    303570
    304         INPUT:
    305 
    306         - ``cartan_type`` -- The Cartan type.
    307         - ``B``           -- A list of dimensions of rectangles by `[r, c]`
    308             where `r` is the number of rows and `c` is the number of columns.
     571        The input ``classical_ct`` is the classical Cartan type to run the
     572        algorithm on and is only meant to be used internally.
    309573
    310574        EXAMPLES::
    311575
    312             sage: KT = KleberTree(['D', 3], [[1,1], [1,1]]); KT
    313             Kleber tree of Cartan type ['D', 3] and root weight [2, 0, 0]
     576            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
     577            sage: KT = KleberTree(['D', 3, 1], [[1,1], [1,1]]); KT
     578            Kleber tree of Cartan type ['D', 3, 1] and B = ((1, 1), (1, 1))
    314579            sage: TestSuite(KT).run(skip="_test_elements")
    315580        """
    316581        Parent.__init__(self, category=FiniteEnumeratedSets())
    317582
    318583        self._cartan_type = cartan_type
    319         self.dims = B
    320         n = self._cartan_type.n
     584        self.B = B
     585        self._classical_ct = classical_ct
     586        self._build_tree(B)
     587        self._latex_options = dict(edge_labels=True, use_vector_notation=False,
     588                                  hspace=2.5, vspace=min(-2.5, -0.75*self._classical_ct.rank()))
     589
     590    def latex_options(self, **options):
     591        """
     592        Return the current latex options if no arguments are passed, otherwise
     593        set the corresponding latex option.
     594
     595        OPTIONS:
     596
     597        - ``hspace`` -- (default: `2.5`) the horizontal spacing of the
     598          tree nodes
     599        - ``vspace`` -- (default: ``x``) the vertical spacing of the tree
     600          nodes, here ``x`` is the minimum of `-2.5` or `-.75n` where `n` is
     601          the rank of the classical type
     602        - ``edge_labels`` -- (default: ``True``) display edge labels
     603        - ``use_vector_notation`` -- (default: ``False``) display edge labels
     604          using vector notation instead of a linear combination
     605
     606        EXAMPLES::
     607
     608            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
     609            sage: KT = KleberTree(['D', 3, 1], [[2,1], [2,1]])
     610            sage: KT.latex_options(vspace=-4, use_vector_notation=True)
     611            sage: sorted(KT.latex_options().items())
     612            [('edge_labels', True), ('hspace', 2.5), ('use_vector_notation', True), ('vspace', -4)]
     613        """
     614        if len(options) == 0:
     615            from copy import copy
     616            return copy(self._latex_options)
     617        for k in options:
     618            self._latex_options[k] = options[k]
     619
     620    def _latex_(self):
     621        r"""
     622        Return a latex representation of this Kleber tree.
     623
     624        .. SEEALSO::
     625
     626            :meth:`latex_options()`
     627
     628        EXAMPLES::
     629
     630            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
     631            sage: KT = KleberTree(['D', 3, 1], [[2,1], [2,1]])
     632            sage: KT._latex_()
     633            '\\begin{tikzpicture}...\\end{tikzpicture}'
     634        """
     635        from sage.graphs.graph_latex import setup_latex_preamble
     636        setup_latex_preamble()
     637
     638        return "\\begin{tikzpicture}\n" + \
     639               _draw_tree(self.root, **self._latex_options) \
     640               + "\\end{tikzpicture}"
     641
     642    def _build_tree(self, B):
     643        """
     644        Build the Kleber tree.
     645
     646        TESTS:
     647
     648        This is called from the constructor::
     649
     650            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
     651            sage: KT = KleberTree(['A',3,1], [[2,2]]) # indirect doctest
     652        """
    321653        # Create an empty node at first step
    322         self.root = KleberTreeNode(self, self._cartan_type.root_system().weight_space().zero(),
    323                                    self._cartan_type.root_system().root_space().zero())
     654        self.root = KleberTreeNode(self, self._classical_ct.root_system().weight_space().zero(),
     655                                   self._classical_ct.root_system().root_space().zero())
    324656        full_list = [self.root] # The list of tree nodes
    325657
     658        n = self._classical_ct.rank()
     659
    326660        # Convert the B values into an L matrix
    327661        L = []
    328662        for i in range(0, n):
    class KleberTree(Parent, UniqueRepresent 
    335669            L[dim[0] - 1][dim[1] - 1] += 1 # The -1 is b/c of indexing
    336670
    337671        # Perform a special case of the algorithm for the root node
    338         weight_basis = self._cartan_type.root_system().weight_space().basis()
     672        weight_basis = self._classical_ct.root_system().weight_space().basis()
    339673        for a in range(n):
    340674            self.root.weight += sum(L[a]) * weight_basis[a+1] # Add 1 for indexing
    341675        new_children = []
    342676        for new_child in self._children_root_iter():
    343             new_children.append(new_child)
    344             self.root.children.append(new_child)
    345             full_list.append(new_child)
     677            if not self._prune(new_child, 1):
     678                new_children.append(new_child)
     679                self.root.children.append(new_child)
     680                full_list.append(new_child)
    346681
    347682        depth = 1
    348683        growth = True
    class KleberTree(Parent, UniqueRepresent 
    362697
    363698                    if x in leaves:
    364699                        for new_child in self._children_iter(x):
    365                             new_children.append(new_child)
     700                            if not self._prune(new_child, depth):
     701                                new_children.append(new_child)
    366702            else:
    367703                for x in leaves:
    368704                    for new_child in self._children_iter(x):
    369                         new_children.append(new_child)
     705                        if not self._prune(new_child, depth):
     706                            new_children.append(new_child)
    370707
    371708            # Connect the new children into the tree
    372709            if len(new_children) > 0:
    class KleberTree(Parent, UniqueRepresent 
    377714
    378715        self._set = full_list
    379716
    380     def _latex_(self, **options):
    381         r"""
    382         Return a latex representation of this Kleber tree.
    383        
    384         EXAMPLES::
    385        
    386             sage: KT = KleberTree(['D', 3], [[2,1], [2,1]])
    387             sage: KT._latex_()   #optional - dot2tex
    388             ...
    389             sage: view(KT, pdflatex=True, tightpage=True) #optional - dot2tex graphviz
    390 
    391         """
    392         if not have_dot2tex():
    393             print "dot2tex not available.  Install after running \'sage -sh\'"
    394             return
    395         G = self.digraph()
    396         G.set_latex_options(format="dot2tex", edge_labels=True, **options)
    397         return G._latex_()
    398 
    399717    def _children_root_iter(self):
    400718        """
    401719        Iterate over the children of the root node.
    402720
    403         Helper iterator to iterate over all children, by generating and/or 
     721        Helper iterator to iterate over all children, by generating and/or
    404722        computing them, of the Kleber tree root.
    405723
    406724        Right now we are just assuming that if a linear combination of positive
    class KleberTree(Parent, UniqueRepresent 
    409727
    410728        TESTS::
    411729
    412             sage: KT = KleberTree(['D', 3], [[1,1], [1,1]])
     730            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
     731            sage: KT = KleberTree(['D', 3, 1], [[1,1], [1,1]])
    413732            sage: for x in KT: x # indirect doctest
    414             ...
    415733            Kleber tree node with weight [2, 0, 0] and upwards edge root [0, 0, 0]
    416734            Kleber tree node with weight [0, 1, 1] and upwards edge root [1, 0, 0]
    417735            Kleber tree node with weight [0, 0, 0] and upwards edge root [2, 1, 1]
    418736        """
    419         n = self._cartan_type.n
    420         cartan_matrix = self._cartan_type.cartan_matrix()
    421         pos_roots = list(self._cartan_type.root_system().root_space().positive_roots())
    422         WS = self._cartan_type.root_system().weight_space()
     737        pos_roots = list(self._classical_ct.root_system().root_space().positive_roots())
     738        WS = self._classical_ct.root_system().weight_space()
    423739        num_pos_roots = len(pos_roots)
    424740        roots_visited = []
    425741
    class KleberTree(Parent, UniqueRepresent 
    431747            # If not, then try it
    432748
    433749            roots_visited.append(root)
    434            
     750
    435751            new_weight = self.root.weight - WS(root)
    436752
    437753            if new_weight.is_dominant():
    class KleberTree(Parent, UniqueRepresent 
    476792        INPUT:
    477793
    478794        - ``node`` -- The current node in the tree whose children we want
    479             to generate
     795          to generate
    480796
    481797        TESTS::
    482798
    483             sage: KT = KleberTree(['D', 4], [[2,2]])
     799            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
     800            sage: KT = KleberTree(['D', 4, 1], [[2,2]])
    484801            sage: KT[1]
    485802            Kleber tree node with weight [0, 1, 0, 0] and upwards edge root [1, 2, 1, 1]
    486803            sage: for x in KT: x
    487             ...
    488804            Kleber tree node with weight [0, 2, 0, 0] and upwards edge root [0, 0, 0, 0]
    489805            Kleber tree node with weight [0, 1, 0, 0] and upwards edge root [1, 2, 1, 1]
    490806            Kleber tree node with weight [0, 0, 0, 0] and upwards edge root [1, 2, 1, 1]
    491807            sage: for x in KT._children_iter(KT[1]): x
    492             ...
    493808            Kleber tree node with weight [0, 0, 0, 0] and upwards edge root [1, 2, 1, 1]
    494809        """
    495         n = self._cartan_type.n
    496         cartan_matrix = self._cartan_type.cartan_matrix()
    497         RS = self._cartan_type.root_system()
    498         WS = RS.weight_space()
     810        RS = self._classical_ct.root_system().root_space()
     811        WS = self._classical_ct.root_system().weight_space()
    499812
    500         L = []
    501         for val in node.up_root.to_vector():
    502             L.append(range(val + 1))
     813        L = [range(val + 1) for val in node.up_root.to_vector()]
    503814
    504         root_list = CartesianProduct(*L).list()
    505         root_list.pop(0) # First element is the zero element
     815        for root in CartesianProduct(*L).list()[1:]: # First element is the zero element
     816            # Convert the list to an honest root in the root space
     817            converted_root = RS.sum_of_terms([[i+1, val] for i, val in enumerate(root)])
    506818
    507         root_basis = RS.root_space().basis()
    508         for root in root_list:
    509             # Convert the list to an honest root in the root space
    510             converted_root = RS.root_space().zero()
    511             for i, val in enumerate(root):
    512                 converted_root += val * root_basis[i+1] # Add 1 for indexing
    513            
    514819            new_weight = node.weight - WS(converted_root)
    515820            if new_weight.is_dominant():
    516821                yield KleberTreeNode(self, new_weight, converted_root, node)
    517                
     822
     823    def _prune(self, new_child, depth):
     824        r"""
     825        Return ``True`` if we are to prune the tree at ``new_child``.
     826
     827        This always returns ``False`` since we do not do any pruning.
     828
     829        EXAMPLES::
     830
     831            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
     832            sage: KT = KleberTree(['A', 2, 1], [[1,1]])
     833            sage: KT._prune(KT.root, 0)
     834            False
     835        """
     836        return False
     837
    518838    def breadth_first_iter(self):
    519839        r"""
    520840        Iterate over all nodes in the tree following a breadth-first traversal.
    521        
     841
    522842        EXAMPLES::
    523        
    524             sage: KT = KleberTree(['A', 3], [[2, 2], [2, 3]])
     843
     844            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
     845            sage: KT = KleberTree(['A', 3, 1], [[2, 2], [2, 3]])
    525846            sage: for x in KT.breadth_first_iter(): x
    526             ...
    527847            Kleber tree node with weight [0, 5, 0] and upwards edge root [0, 0, 0]
    528848            Kleber tree node with weight [1, 3, 1] and upwards edge root [0, 1, 0]
    529849            Kleber tree node with weight [0, 3, 0] and upwards edge root [1, 2, 1]
    class KleberTree(Parent, UniqueRepresent 
    531851            Kleber tree node with weight [1, 1, 1] and upwards edge root [0, 1, 0]
    532852            Kleber tree node with weight [0, 1, 0] and upwards edge root [1, 2, 1]
    533853        """
    534        
    535854        cur = []
    536855        next = [self.root]
    537856        while len(next) > 0:
    class KleberTree(Parent, UniqueRepresent 
    540859            for node in cur:
    541860                yield node
    542861                next.extend(node.children)
    543            
    544862
    545     def depth_first_iter(self, cur=None):
     863    def depth_first_iter(self):
    546864        r"""
    547865        Iterate (recursively) over the nodes in the tree following a
    548866        depth-first traversal.
    549867
    550868        EXAMPLES::
    551869
    552             sage: KT = KleberTree(['A', 3], [[2, 2], [2, 3]])
     870            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
     871            sage: KT = KleberTree(['A', 3, 1], [[2, 2], [2, 3]])
    553872            sage: for x in KT.depth_first_iter(): x
    554             ...
    555873            Kleber tree node with weight [0, 5, 0] and upwards edge root [0, 0, 0]
    556874            Kleber tree node with weight [1, 3, 1] and upwards edge root [0, 1, 0]
    557875            Kleber tree node with weight [2, 1, 2] and upwards edge root [0, 1, 0]
    class KleberTree(Parent, UniqueRepresent 
    559877            Kleber tree node with weight [1, 1, 1] and upwards edge root [0, 1, 0]
    560878            Kleber tree node with weight [0, 1, 0] and upwards edge root [1, 2, 1]
    561879        """
     880        return self._depth_first_iter(None)
    562881
     882    def _depth_first_iter(self, cur):
     883        r"""
     884        Helper recursive function used in depth-first iteration.
     885
     886        EXAMPLES::
     887
     888            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
     889            sage: KT = KleberTree(['A', 3, 1], [[2, 2], [2, 3]])
     890            sage: for x in KT._depth_first_iter(None): x
     891            Kleber tree node with weight [0, 5, 0] and upwards edge root [0, 0, 0]
     892            Kleber tree node with weight [1, 3, 1] and upwards edge root [0, 1, 0]
     893            Kleber tree node with weight [2, 1, 2] and upwards edge root [0, 1, 0]
     894            Kleber tree node with weight [0, 3, 0] and upwards edge root [1, 2, 1]
     895            Kleber tree node with weight [1, 1, 1] and upwards edge root [0, 1, 0]
     896            Kleber tree node with weight [0, 1, 0] and upwards edge root [1, 2, 1]
     897        """
    563898        if cur is None:
    564899            cur = self.root
    565900
    566901        yield cur
    567902
    568903        for child in cur.children:
    569             for x in self.depth_first_iter(child):
     904            for x in self._depth_first_iter(child):
    570905                yield x
    571                
     906
    572907    __iter__ = breadth_first_iter
    573908
    574909    def _repr_(self):
    class KleberTree(Parent, UniqueRepresent 
    577912
    578913        EXAMPLES::
    579914
    580             sage: KT = KleberTree(['D', 4], [[2, 2]]); KT # indirect doctest
    581             Kleber tree of Cartan type ['D', 4] and root weight [0, 2, 0, 0]
     915            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
     916            sage: KleberTree(['D', 4, 1], [[2, 2]]) # indirect doctest
     917            Kleber tree of Cartan type ['D', 4, 1] and B = ((2, 2),)
    582918        """
    583         ret_str = "Kleber tree of Cartan type " + repr(self._cartan_type) \
    584             + " and root weight " + repr(list(self.root.weight.to_vector()))
    585         return ret_str
     919        return "Kleber tree of Cartan type %s and B = %s"%(repr(self._cartan_type), self.B)
    586920
    587921    def cartan_type(self):
    588922        r"""
    class KleberTree(Parent, UniqueRepresent 
    590924
    591925        EXAMPLES::
    592926
    593             sage: KT = KleberTree(['A', 3], [[1,1]])
     927            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
     928            sage: KT = KleberTree(['A', 3, 1], [[1,1]])
    594929            sage: KT.cartan_type()
    595             ['A', 3]
     930            ['A', 3, 1]
    596931        """
    597         return(self._cartan_type)
     932        return self._cartan_type
    598933
    599934    def digraph(self):
    600935        r"""
    class KleberTree(Parent, UniqueRepresent 
    602937
    603938        EXAMPLES::
    604939
    605             sage: KT = KleberTree(['D', 4], [[2, 2]])
    606             sage: KT.digraph()
     940            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
     941            sage: KT = KleberTree(['D', 4, 1], [[2, 2]])
     942            sage: KT.digraph() # optional - dot2tex, graphviz
    607943            Digraph on 3 vertices
    608944        """
    609945        d = {}
    610         for x in self:
     946        for x in self.breadth_first_iter():
    611947            d[x] = {}
    612948            if x.parent_node is None:
    613949                continue
    class KleberTree(Parent, UniqueRepresent 
    625961
    626962        EXAMPLES::
    627963
    628             sage: KT = KleberTree(['D', 4], [[2, 2]])
    629             sage: print(KT.plot())
     964            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
     965            sage: KT = KleberTree(['D', 4, 1], [[2, 2]])
     966            sage: print(KT.plot()) # optional - dot2tex, graphviz
    630967            Graphics object consisting of 8 graphics primitives
    631968        """
    632969        return self.digraph().plot(edge_labels=True, vertex_size=0, **options)
    633    
     970
    634971    def _element_constructor_(self, node_weight, dominant_root, parent_node=None):
    635972        """
    636         Construct a KleberTree.
     973        Construct a Kleber tree node.
    637974
    638975        EXAMPLES::
    639        
     976
     977            sage: from sage.combinat.rigged_configurations.kleber_tree import KleberTree
    640978            sage: RS = RootSystem(['A', 2])
    641979            sage: WS = RS.weight_space()
    642980            sage: R = RS.root_space()
    643             sage: KT = KleberTree(['A', 2], [[1,1]])
     981            sage: KT = KleberTree(['A', 2, 1], [[1,1]])
    644982            sage: root = KT(WS.sum_of_terms([(1,5), (2,2)]), R.zero()); root # indirect doctest
    645983            Kleber tree node with weight [5, 2] and upwards edge root [0, 0]
    646984            sage: child = KT(WS.sum_of_terms([(1,5), (2,1)]), R.zero(), root); child # indirect doctest
    647985            Kleber tree node with weight [5, 1] and upwards edge root [0, 0]
    648986            sage: child.parent_node
    649987            Kleber tree node with weight [5, 2] and upwards edge root [0, 0]
    650 
    651988        """
    652989        return self.element_class(self, node_weight, dominant_root, parent_node)
    653    
     990
    654991    Element = KleberTreeNode
    655992
     993class VirtualKleberTree(KleberTree):
     994    """
     995    A virtual Kleber tree.
     996
     997    We can use a modified version of the Kleber algorithm called the virtual
     998    Kleber algorithm [OSS03]_ to compute all admissible rigged configurations
     999    for non-simply-laced types. This uses the following embeddings
     1000    into the simply-laced types:
     1001
     1002    .. MATH::
     1003
     1004        C_n^{(1)}, A_{2n}^{(2)}, A_{2n}^{(2)\dagger}, D_{n+1}^{(2)}
     1005        \hookrightarrow A_{2n-1}^{(1)}
     1006
     1007        A_{2n-1}^{(2)}, B_n^{(1)} \hookrightarrow D_{n+1}^{(1)}
     1008
     1009        E_6^{(2)}, F_4^{(1)} \hookrightarrow E_6^{(1)}
     1010
     1011        D_4^{(3)}, G_2^{(1)} \hookrightarrow D_4^{(1)}
     1012
     1013    One then selects the subset of admissible nodes which are translates of
     1014    the virtual requirements. In the graph, the selected nodes are indicated
     1015    by brackets `[]`.
     1016
     1017    .. NOTE::
     1018
     1019        Because these are virtual nodes, all information is given
     1020        in the corresponding simply-laced type.
     1021
     1022    .. SEEALSO::
     1023
     1024        For more on the Kleber algorithm, see :class:`KleberTree`.
     1025
     1026    REFERENCES:
     1027
     1028    .. [OSS03] Masato Okado, Anne Schilling, and Mark Shimozono.
     1029       *Virtual crystals and Klebers algorithm*. Commun. Math. Phys. **238**
     1030       (2003). 187-209. :arxiv:`math.QA/0209082`.
     1031
     1032    INPUT:
     1033
     1034    - ``cartan_type`` -- an affine non-simply-laced Cartan type
     1035
     1036    - ``B`` -- a list of dimensions of rectangles by `[r, c]`
     1037      where `r` is the number of rows and `c` is the number of columns
     1038
     1039    EXAMPLES::
     1040
     1041        sage: from sage.combinat.rigged_configurations.kleber_tree import VirtualKleberTree
     1042        sage: KT = VirtualKleberTree(['C', 4, 1], [[2,2]])
     1043        sage: KT.cardinality()
     1044        3
     1045        sage: KT.base_tree().cardinality()
     1046        6
     1047        sage: KT = VirtualKleberTree(['C', 4, 1], [[4,5]])
     1048        sage: KT.cardinality()
     1049        1
     1050        sage: KT = VirtualKleberTree(['D', 5, 2], [[2,1], [1,1]])
     1051        sage: KT.cardinality()
     1052        8
     1053        sage: KT = VirtualKleberTree(CartanType(['A', 4, 2]).dual(), [[1,1], [2,2]])
     1054        sage: KT.cardinality()
     1055        15
     1056    """
     1057    @staticmethod
     1058    def __classcall_private__(cls, cartan_type, B):
     1059        """
     1060        Normalize the input arguments to ensure unique representation.
     1061
     1062        EXAMPLES::
     1063
     1064            sage: from sage.combinat.rigged_configurations.kleber_tree import VirtualKleberTree
     1065            sage: KT1 = VirtualKleberTree(CartanType(['C',3,1]).as_folding(), [[2,2]])
     1066            sage: KT2 = VirtualKleberTree(CartanType(['C',3,1]), [(2,2)])
     1067            sage: KT3 = VirtualKleberTree(['C',3,1], ((2,2),))
     1068            sage: KT2 is KT1, KT3 is KT1
     1069            (True, True)
     1070        """
     1071        cartan_type = CartanType(cartan_type)
     1072        # Standardize B input into a tuple of tuples
     1073        B = tuple(map(tuple, B))
     1074        if cartan_type.type() == 'BC' or cartan_type.dual().type() == 'BC':
     1075            # Types A_{2n}^{(2)} and its dual
     1076            return KleberTreeTypeA2Even(cartan_type, B)
     1077        if cartan_type.classical().is_simply_laced():
     1078            raise ValueError("use KleberTree for simply-laced types")
     1079        return super(VirtualKleberTree, cls).__classcall__(cls, cartan_type, B)
     1080
     1081    def __init__(self, cartan_type, B):
     1082        """
     1083        Initialize ``self``.
     1084
     1085        EXAMPLES::
     1086
     1087            sage: from sage.combinat.rigged_configurations.kleber_tree import VirtualKleberTree
     1088            sage: KT = VirtualKleberTree(['C',4,1], [[2,2]])
     1089            sage: TestSuite(KT).run(skip="_test_elements")
     1090        """
     1091        self._folded_ct = cartan_type.as_folding()
     1092        virtual_dims = []
     1093        self.base_dims = B
     1094        sigma = self._folded_ct.folding_orbit()
     1095        gamma = self._folded_ct.scaling_factors()
     1096        classical_ct = self._folded_ct.folding_of().classical()
     1097        for r,s in B:
     1098            for i in sigma[r]:
     1099                virtual_dims.append([i, s * gamma[r]])
     1100
     1101        KleberTree.__init__(self, cartan_type, virtual_dims, classical_ct)
     1102
     1103    def _repr_(self):
     1104        """
     1105        Return a text representation of this Kleber tree.
     1106
     1107        EXAMPLES::
     1108
     1109            sage: from sage.combinat.rigged_configurations.kleber_tree import VirtualKleberTree
     1110            sage: VirtualKleberTree(['C', 4, 1], [[2, 2]])
     1111            Virtual Kleber tree of Cartan type ['C', 4, 1] and B = ((2, 2),)
     1112        """
     1113        return "Virtual Kleber tree of Cartan type %s and B = %s"%(repr(self._cartan_type), self.base_dims)
     1114
     1115    def _prune(self, new_child, depth):
     1116        r"""
     1117        Return ``True`` if we are to prune the tree at ``new_child``.
     1118
     1119        Suppose `\lambda` is the weight of the child we want to add at depth
     1120        `\ell`. We prune ``new_child`` if either of the following conditions
     1121        are not satisfied:
     1122
     1123        1. `(\lambda \mid \alpha_a) = (\lambda \mid \alpha_b)` if `a` and `b`
     1124           are in the same `\sigma`-orbit.
     1125        2. If `\ell - 1 \notin \gamma_a \ZZ`, then the `a`-th component of
     1126           ``up_root`` of ``new_child`` must equal the `a`-th component of
     1127           ``up_root`` of its ``parent_node``. Note that from condition 1,
     1128           we only need to check one such `a` from each `\sigma`-orbit.
     1129
     1130        These conditions are equivalent to Definition 4.1 in [OSS03]_.
     1131
     1132        EXAMPLES::
     1133
     1134            sage: from sage.combinat.rigged_configurations.kleber_tree import VirtualKleberTree
     1135            sage: RS = RootSystem(['A', 3])
     1136            sage: WS = RS.weight_space()
     1137            sage: R = RS.root_space()
     1138            sage: KT = VirtualKleberTree(['C',2,1], [[1,2],[1,1],[2,1]])
     1139            sage: x = KT(WS.sum_of_terms([(1,1), (2,1), (3,3)]), R.sum_of_terms([(1,2),(2,2),(3,1)]), KT.root)
     1140            sage: KT._prune(x, 1)
     1141            True
     1142        """
     1143        sigma = self._folded_ct._orbit
     1144        for orbit in sigma[1:]:
     1145            start = new_child.weight[orbit[0]]
     1146            for i in orbit[1:]:
     1147                if new_child.weight[i] != start:
     1148                    return True
     1149        gamma = self._folded_ct.scaling_factors()
     1150        for a in range(1, len(gamma)):
     1151            if (depth - 1) % gamma[a] != 0 and new_child.up_root[sigma[a][0]] \
     1152              != new_child.parent_node.up_root[sigma[a][0]]:
     1153                return True
     1154        return False
     1155
     1156    def breadth_first_iter(self, all_nodes=False):
     1157        r"""
     1158        Iterate over all nodes in the tree following a breadth-first traversal.
     1159
     1160        INPUT:
     1161
     1162        - ``all_nodes`` -- (default: ``False``) if ``True``, output all
     1163          nodes in the tree
     1164
     1165        EXAMPLES::
     1166
     1167            sage: from sage.combinat.rigged_configurations.kleber_tree import VirtualKleberTree
     1168            sage: KT = VirtualKleberTree(['C', 2, 1], [[1,1], [2,1]])
     1169            sage: for x in KT.breadth_first_iter(): x
     1170            Kleber tree node with weight [1, 2, 1] and upwards edge root [0, 0, 0]
     1171            Kleber tree node with weight [1, 0, 1] and upwards edge root [0, 1, 0]
     1172            sage: for x in KT.breadth_first_iter(True): x
     1173            Kleber tree node with weight [1, 2, 1] and upwards edge root [0, 0, 0]
     1174            Kleber tree node with weight [0, 2, 0] and upwards edge root [1, 1, 1]
     1175            Kleber tree node with weight [1, 0, 1] and upwards edge root [0, 1, 0]
     1176        """
     1177        s_factors = self._folded_ct.scaling_factors()
     1178        gamma = max(s_factors)
     1179        # Subtract 1 for indexing
     1180        if gamma > 1:
     1181            sigma = self._folded_ct.folding_orbit()
     1182            L = [sigma[a][0] for a in range(1, len(s_factors))
     1183                 if s_factors[a] == gamma]
     1184        else:
     1185            L = []
     1186
     1187        for x in KleberTree.breadth_first_iter(self):
     1188            if all_nodes or (x.depth) % gamma == 0 or all(x.up_root[a] == 0 for a in L):
     1189                yield x
     1190
     1191    def depth_first_iter(self, all_nodes=False):
     1192        r"""
     1193        Iterate (recursively) over the nodes in the tree following a
     1194        depth-first traversal.
     1195
     1196        INPUT:
     1197
     1198        - ``all_nodes`` -- (default: ``False``) if ``True``, output all
     1199          nodes in the tree
     1200
     1201        EXAMPLES::
     1202
     1203            sage: from sage.combinat.rigged_configurations.kleber_tree import VirtualKleberTree
     1204            sage: KT = VirtualKleberTree(['C', 2, 1], [[1,1], [2,1]])
     1205            sage: for x in KT.depth_first_iter(): x
     1206            Kleber tree node with weight [1, 2, 1] and upwards edge root [0, 0, 0]
     1207            Kleber tree node with weight [1, 0, 1] and upwards edge root [0, 1, 0]
     1208            sage: for x in KT.depth_first_iter(True): x
     1209            Kleber tree node with weight [1, 2, 1] and upwards edge root [0, 0, 0]
     1210            Kleber tree node with weight [0, 2, 0] and upwards edge root [1, 1, 1]
     1211            Kleber tree node with weight [1, 0, 1] and upwards edge root [0, 1, 0]
     1212        """
     1213        s_factors = self._folded_ct.scaling_factors()
     1214        gamma = max(s_factors)
     1215        # Subtract 1 for indexing
     1216        if gamma > 1:
     1217            sigma = self._folded_ct.folding_orbit()
     1218            L = [sigma[a][0] for a in range(1, len(s_factors))
     1219                 if s_factors[a] == gamma]
     1220        else:
     1221            L = []
     1222
     1223        for x in self._depth_first_iter(None):
     1224            if all_nodes or (x.depth) % gamma == 0 or all(x.up_root[a] == 0 for a in L):
     1225                yield x
     1226
     1227    __iter__ = breadth_first_iter
     1228
     1229    def base_tree(self):
     1230        """
     1231        Return the underlying virtual Kleber tree associated to ``self``.
     1232
     1233        EXAMPLES::
     1234
     1235            sage: from sage.combinat.rigged_configurations.kleber_tree import VirtualKleberTree
     1236            sage: KT = VirtualKleberTree(['C', 4, 1], [[2,2]])
     1237            sage: KT.base_tree()
     1238            Kleber tree of Cartan type ['A', 7, 1] and B = ((2, 2), (6, 2))
     1239        """
     1240        return KleberTree(self._folded_ct.folding_of(), self.B)
     1241
     1242class KleberTreeTypeA2Even(VirtualKleberTree):
     1243    r"""
     1244    Kleber tree for types `A_{2n}^{(2)}` and `A_{2n}^{(2)\dagger}`.
     1245
     1246    Note that here for `A_{2n}^{(2)}` we use `\tilde{\gamma}_a` in place of
     1247    `\gamma_a` in constructing the virtual Kleber tree, and so we end up
     1248    selecting all nodes since `\tilde{\gamma}_a = 1` for all `a \in
     1249    \overline{I}`. For type `A_{2n}^{(2)\dagger}`, we have `\gamma_a = 1`
     1250    for all `a \in \overline{I}`.
     1251
     1252    .. SEEALSO::
     1253
     1254        :class:`VirtualKleberTree`
     1255    """
     1256    @staticmethod
     1257    def __classcall_private__(cls, cartan_type, B):
     1258        """
     1259        Normalize the input arguments to ensure unique representation.
     1260
     1261        EXAMPLES::
     1262
     1263            sage: from sage.combinat.rigged_configurations.kleber_tree import VirtualKleberTree
     1264            sage: KT1 = VirtualKleberTree(CartanType(['A',6,2]), [[2,2]])
     1265            sage: KT2 = VirtualKleberTree(['A',6,2], [(2,2)])
     1266            sage: KT3 = VirtualKleberTree(['A',6,2], ((2,2),))
     1267            sage: KT2 is KT1, KT3 is KT1
     1268            (True, True)
     1269        """
     1270        cartan_type = CartanType(cartan_type)
     1271        # Standardize B input into a tuple of tuples
     1272        B = tuple(map(tuple, B))
     1273        return super(KleberTreeTypeA2Even, cls).__classcall__(cls, cartan_type, B)
     1274
     1275    def __init__(self, cartan_type, B):
     1276        """
     1277        Initialize ``self``.
     1278
     1279        EXAMPLES::
     1280
     1281            sage: from sage.combinat.rigged_configurations.kleber_tree import VirtualKleberTree
     1282            sage: KT = VirtualKleberTree(['A',6,2], [[2,2]]); KT
     1283            Virtual Kleber tree of Cartan type ['BC', 3, 2] and B = ((2, 2),)
     1284            sage: TestSuite(KT).run(skip="_test_elements")
     1285        """
     1286        self._folded_ct = cartan_type.as_folding()
     1287        virtual_dims = []
     1288        n = cartan_type.classical().rank()
     1289        self.base_dims = B
     1290        sigma = self._folded_ct.folding_orbit()
     1291        classical_ct = self._folded_ct.folding_of().classical()
     1292        for r,s in B:
     1293            if r == n:
     1294                virtual_dims.extend([[n, s], [n, s]])
     1295            else:
     1296                for i in sigma[r]:
     1297                    virtual_dims.append([i, s])
     1298
     1299        KleberTree.__init__(self, cartan_type, virtual_dims, classical_ct)
     1300
     1301    def __iter__(self):
     1302        """
     1303        Iterate over all of the nodes.
     1304
     1305        EXAMPLES::
     1306
     1307            sage: from sage.combinat.rigged_configurations.kleber_tree import VirtualKleberTree
     1308            sage: KT = VirtualKleberTree(['A',6,2], [[2,2]])
     1309            sage: L = [x for x in KT]
     1310            sage: len(L) == KT.cardinality()
     1311            True
     1312        """
     1313        return KleberTree.__iter__(self)
     1314
     1315    def _prune(self, new_child, depth):
     1316        r"""
     1317        Return ``True`` if we are to prune the tree at ``new_child``.
     1318
     1319        Suppose `\lambda` is the weight of the child we want to add at
     1320        depth `\ell`. We prune ``new_child`` if `(\lambda \mid \alpha_a)
     1321        \neq (\lambda \mid \alpha_b)` if `a` and `b` are in the same
     1322        `\sigma`-orbit.
     1323
     1324        These conditions are equivalent to Definition 4.1 in [OSS03]_ by using
     1325        `\tilde{\gamma}`, and since `\tilde{\gamma}_a = 1` for all `a`, the
     1326        second condition becomes vacuous.
     1327
     1328        EXAMPLES::
     1329
     1330            sage: from sage.combinat.rigged_configurations.kleber_tree import VirtualKleberTree
     1331            sage: RS = RootSystem(['A', 5])
     1332            sage: WS = RS.weight_space()
     1333            sage: R = RS.root_space()
     1334            sage: KT = VirtualKleberTree(['A',6,2], [[2,2]])
     1335            sage: x = KT(WS.sum_of_terms([(2,1), (4,1)]), R.sum_of_terms([(1,1),(2,2),(3,2),(4,2),(5,1)]), KT.root)
     1336            sage: KT._prune(x, 1)
     1337            False
     1338        """
     1339        sigma = self._folded_ct._orbit
     1340        for orbit in sigma[1:]:
     1341            start = new_child.weight[orbit[0]]
     1342            for i in orbit[1:]:
     1343                if new_child.weight[i] != start:
     1344                    return True
     1345        return False
     1346
     1347    def breadth_first_iter(self, all_nodes=False):
     1348        r"""
     1349        Iterate over all nodes in the tree following a breadth-first traversal.
     1350
     1351        INPUT:
     1352
     1353        - ``all_nodes`` -- (default: ``False``) if ``True``, output all
     1354          nodes in the tree
     1355
     1356        EXAMPLES::
     1357
     1358            sage: from sage.combinat.rigged_configurations.kleber_tree import VirtualKleberTree
     1359            sage: KT = VirtualKleberTree(['A', 4, 2], [[2,1]])
     1360            sage: for x in KT.breadth_first_iter(): x
     1361            Kleber tree node with weight [0, 2, 0] and upwards edge root [0, 0, 0]
     1362            Kleber tree node with weight [1, 0, 1] and upwards edge root [0, 1, 0]
     1363            Kleber tree node with weight [0, 0, 0] and upwards edge root [1, 2, 1]
     1364            sage: for x in KT.breadth_first_iter(True): x
     1365            Kleber tree node with weight [0, 2, 0] and upwards edge root [0, 0, 0]
     1366            Kleber tree node with weight [1, 0, 1] and upwards edge root [0, 1, 0]
     1367            Kleber tree node with weight [0, 0, 0] and upwards edge root [1, 2, 1]
     1368        """
     1369        return KleberTree.breadth_first_iter(self)
     1370
     1371    def depth_first_iter(self, all_nodes=False):
     1372        r"""
     1373        Iterate (recursively) over the nodes in the tree following a
     1374        depth-first traversal.
     1375
     1376        INPUT:
     1377
     1378        - ``all_nodes`` -- (default: ``False``) if ``True``, output all
     1379          nodes in the tree
     1380
     1381        EXAMPLES::
     1382
     1383            sage: from sage.combinat.rigged_configurations.kleber_tree import VirtualKleberTree
     1384            sage: KT = VirtualKleberTree(['A', 4, 2], [[2,1]])
     1385            sage: for x in KT.depth_first_iter(): x
     1386            Kleber tree node with weight [0, 2, 0] and upwards edge root [0, 0, 0]
     1387            Kleber tree node with weight [1, 0, 1] and upwards edge root [0, 1, 0]
     1388            Kleber tree node with weight [0, 0, 0] and upwards edge root [1, 2, 1]
     1389            sage: for x in KT.depth_first_iter(True): x
     1390            Kleber tree node with weight [0, 2, 0] and upwards edge root [0, 0, 0]
     1391            Kleber tree node with weight [1, 0, 1] and upwards edge root [0, 1, 0]
     1392            Kleber tree node with weight [0, 0, 0] and upwards edge root [1, 2, 1]
     1393        """
     1394        return KleberTree.depth_first_iter(self)
     1395
  • sage/combinat/rigged_configurations/rigged_configurations.py

    diff --git a/sage/combinat/rigged_configurations/rigged_configurations.py b/sage/combinat/rigged_configurations/rigged_configurations.py
    a b class AbstractRiggedConfigurations(Uniqu 
    514514
    515515            sage: RC = RiggedConfigurations(['A', 4, 1], [[2, 2]])
    516516            sage: RC.kleber_tree
    517             Kleber tree of Cartan type ['A', 4] and root weight [0, 2, 0, 0]
     517            Kleber tree of Cartan type ['A', 4, 1] and B = ((2, 2),)
    518518        """
    519         #return KleberTree(self._cartan_type.classical(), self.dims)
    520         return KleberTree(self._cartan_type, self.dims)
     519        return KleberTree(self._affine_ct, self.dims)
    521520
    522521    def tensor_product_of_Kirillov_Reshetikhin_tableaux(self):
    523522        """