def __classcall_private__(cls, cartan_type, shapes=None, shape=None): """ Normalizes the input arguments to ensure unique representation, and to delegate the construction of spin tableaux. EXAMPLES:: sage: T1 = CrystalOfTableaux(CartanType(['A',3]), shape = [2,2]) sage: T2 = CrystalOfTableaux(['A',3], shape = (2,2)) sage: T3 = CrystalOfTableaux(['A',3], shapes = ([2,2],)) sage: T2 is T1, T3 is T1 (True, True) """ cartan_type = CartanType(cartan_type) n = cartan_type.rank() # standardize shape/shapes input into a tuple of tuples assert operator.xor(shape is not None, shapes is not None) if shape is not None: shapes = (shape, ) spin_shapes = tuple(tuple(shape) for shape in shapes) try: shapes = tuple( tuple(trunc(i) for i in shape) for shape in spin_shapes) except StandardError: raise ValueError( "shapes should all be partitions or half-integer partitions") if spin_shapes == shapes: return super(CrystalOfTableaux, cls).__classcall__(cls, cartan_type, shapes) # Handle the construction of a crystals of spin tableaux # Caveat: this currently only supports all shapes being half # integer partitions of length the rank for type B and D. In # particular, for type D, the spins all have to be plus or all # minus spins assert all(len(sh) == n for sh in shapes), \ "the length of all half-integer partition shapes should be the rank" assert all(2*i % 2 == 1 for shape in spin_shapes for i in shape), \ "shapes should be either all partitions or all half-integer partitions" if cartan_type.type() == 'D': if all(i >= 0 for shape in spin_shapes for i in shape): S = CrystalOfSpinsPlus(cartan_type) elif all(shape[-1] < 0 for shape in spin_shapes): S = CrystalOfSpinsMinus(cartan_type) else: raise ValueError, "In type D spins should all be positive or negative" else: assert all( i >= 0 for shape in spin_shapes for i in shape), \ "shapes should all be partitions" S = CrystalOfSpins(cartan_type) B = CrystalOfTableaux(cartan_type, shapes=shapes) T = TensorProductOfCrystals(S, B, generators=[[S.module_generators[0], x] for x in B.module_generators]) T.rename("The crystal of tableaux of type %s and shape(s) %s" % (cartan_type, list(list(shape) for shape in spin_shapes))) T.shapes = spin_shapes return T
def __classcall_private__(cls, cartan_type, shapes = None, shape = None): """ Normalizes the input arguments to ensure unique representation, and to delegate the construction of spin tableaux. EXAMPLES:: sage: T1 = CrystalOfTableaux(CartanType(['A',3]), shape = [2,2]) sage: T2 = CrystalOfTableaux(['A',3], shape = (2,2)) sage: T3 = CrystalOfTableaux(['A',3], shapes = ([2,2],)) sage: T2 is T1, T3 is T1 (True, True) """ cartan_type = CartanType(cartan_type) n = cartan_type.rank() # standardize shape/shapes input into a tuple of tuples assert operator.xor(shape is not None, shapes is not None) if shape is not None: shapes = (shape,) spin_shapes = tuple( tuple(shape) for shape in shapes ) try: shapes = tuple( tuple(trunc(i) for i in shape) for shape in spin_shapes ) except StandardError: raise ValueError("shapes should all be partitions or half-integer partitions") if spin_shapes == shapes: return super(CrystalOfTableaux, cls).__classcall__(cls, cartan_type, shapes) # Handle the construction of a crystals of spin tableaux # Caveat: this currently only supports all shapes being half # integer partitions of length the rank for type B and D. In # particular, for type D, the spins all have to be plus or all # minus spins assert all(len(sh) == n for sh in shapes), \ "the length of all half-integer partition shapes should be the rank" assert all(2*i % 2 == 1 for shape in spin_shapes for i in shape), \ "shapes should be either all partitions or all half-integer partitions" if cartan_type.type() == 'D': if all( i >= 0 for shape in spin_shapes for i in shape): S = CrystalOfSpinsPlus(cartan_type) elif all(shape[-1]<0 for shape in spin_shapes): S = CrystalOfSpinsMinus(cartan_type) else: raise ValueError, "In type D spins should all be positive or negative" else: assert all( i >= 0 for shape in spin_shapes for i in shape), \ "shapes should all be partitions" S = CrystalOfSpins(cartan_type) B = CrystalOfTableaux(cartan_type, shapes = shapes) T = TensorProductOfCrystals(S,B, generators=[[S.module_generators[0],x] for x in B.module_generators]) T.rename("The crystal of tableaux of type %s and shape(s) %s"%(cartan_type, list(list(shape) for shape in spin_shapes))) T.shapes = spin_shapes return T
def __classcall_private__(cls, R, cartan_type): """ Return the correct parent based on input. EXAMPLES:: sage: lie_algebras.ClassicalMatrix(QQ, ['A', 4]) Special linear Lie algebra of rank 5 over Rational Field sage: lie_algebras.ClassicalMatrix(QQ, CartanType(['B',4])) Special orthogonal Lie algebra of rank 9 over Rational Field sage: lie_algebras.ClassicalMatrix(QQ, 'C4') Symplectic Lie algebra of rank 8 over Rational Field sage: lie_algebras.ClassicalMatrix(QQ, cartan_type=['D',4]) Special orthogonal Lie algebra of rank 8 over Rational Field """ if isinstance(cartan_type, (CartanMatrix, DynkinDiagram_class)): cartan_type = cartan_type.cartan_type() else: cartan_type = CartanType(cartan_type) if not cartan_type.is_finite(): raise ValueError("only for finite types") if cartan_type.type() == 'A': return sl(R, cartan_type.rank() + 1) if cartan_type.type() == 'B': return so(R, 2*cartan_type.rank() + 1) if cartan_type.type() == 'C': return sp(R, 2*cartan_type.rank()) if cartan_type.type() == 'D': return so(R, 2*cartan_type.rank()) if cartan_type.type() == 'E': if cartan_type.rank() == 6: return e6(R) if cartan_type.rank() in [7,8]: raise NotImplementedError("not yet implemented") if cartan_type.type() == 'F' and cartan_type.rank() == 4: return f4(R) if cartan_type.type() == 'G' and cartan_type.rank() == 2: return g2(R) raise ValueError("invalid Cartan type")
def Associahedron(cartan_type, backend='ppl'): r""" Construct an associahedron. The generalized associahedron is a polytopal complex with vertices in one-to-one correspondence with clusters in the cluster complex, and with edges between two vertices if and only if the associated two clusters intersect in codimension 1. The associahedron of type `A_n` is one way to realize the classical associahedron as defined in the :wikipedia:`Associahedron`. A polytopal realization of the associahedron can be found in [CFZ2002]_. The implementation is based on [CFZ2002]_, Theorem 1.5, Remark 1.6, and Corollary 1.9. INPUT: - ``cartan_type`` -- a cartan type according to :class:`sage.combinat.root_system.cartan_type.CartanTypeFactory` - ``backend`` -- string (``'ppl'``); the backend to use; see :meth:`sage.geometry.polyhedron.constructor.Polyhedron` EXAMPLES:: sage: Asso = polytopes.associahedron(['A',2]); Asso Generalized associahedron of type ['A', 2] with 5 vertices sage: sorted(Asso.Hrepresentation(), key=repr) [An inequality (-1, 0) x + 1 >= 0, An inequality (0, -1) x + 1 >= 0, An inequality (0, 1) x + 1 >= 0, An inequality (1, 0) x + 1 >= 0, An inequality (1, 1) x + 1 >= 0] sage: Asso.Vrepresentation() (A vertex at (1, -1), A vertex at (1, 1), A vertex at (-1, 1), A vertex at (-1, 0), A vertex at (0, -1)) sage: polytopes.associahedron(['B',2]) Generalized associahedron of type ['B', 2] with 6 vertices The two pictures of [CFZ2002]_ can be recovered with:: sage: Asso = polytopes.associahedron(['A',3]); Asso Generalized associahedron of type ['A', 3] with 14 vertices sage: Asso.plot() # long time Graphics3d Object sage: Asso = polytopes.associahedron(['B',3]); Asso Generalized associahedron of type ['B', 3] with 20 vertices sage: Asso.plot() # long time Graphics3d Object TESTS:: sage: sorted(polytopes.associahedron(['A',3]).vertices()) [A vertex at (-3/2, 0, -1/2), A vertex at (-3/2, 0, 3/2), A vertex at (-3/2, 1, -3/2), A vertex at (-3/2, 2, -3/2), A vertex at (-3/2, 2, 3/2), A vertex at (-1/2, -1, -1/2), A vertex at (-1/2, 0, -3/2), A vertex at (1/2, -2, 1/2), A vertex at (1/2, -2, 3/2), A vertex at (3/2, -2, 1/2), A vertex at (3/2, -2, 3/2), A vertex at (3/2, 0, -3/2), A vertex at (3/2, 2, -3/2), A vertex at (3/2, 2, 3/2)] sage: sorted(polytopes.associahedron(['B',3]).vertices()) [A vertex at (-3, 0, 0), A vertex at (-3, 0, 3), A vertex at (-3, 2, -2), A vertex at (-3, 4, -3), A vertex at (-3, 5, -3), A vertex at (-3, 5, 3), A vertex at (-2, 1, -2), A vertex at (-2, 3, -3), A vertex at (-1, -2, 0), A vertex at (-1, -1, -1), A vertex at (1, -4, 1), A vertex at (1, -3, 0), A vertex at (2, -5, 2), A vertex at (2, -5, 3), A vertex at (3, -5, 2), A vertex at (3, -5, 3), A vertex at (3, -3, 0), A vertex at (3, 3, -3), A vertex at (3, 5, -3), A vertex at (3, 5, 3)] sage: polytopes.associahedron(['A',4]).f_vector() (1, 42, 84, 56, 14, 1) sage: polytopes.associahedron(['B',4]).f_vector() (1, 70, 140, 90, 20, 1) sage: p1 = polytopes.associahedron(['A',4], backend='normaliz') # optional - pynormaliz sage: TestSuite(p1).run(skip='_test_pickling') # optional - pynormaliz sage: p2 = polytopes.associahedron(['A',4], backend='cdd') sage: TestSuite(p2).run() sage: p3 = polytopes.associahedron(['A',4], backend='field') sage: TestSuite(p3).run() """ cartan_type = CartanType(cartan_type) parent = Associahedra(QQ, cartan_type.rank(), backend) return parent(cartan_type)
def Associahedron(cartan_type): r""" Construct an associahedron An Associahedron The generalized associahedron is a polytopal complex with vertices in one-to-one correspondence with clusters in the cluster complex, and with edges between two vertices if and only if the associated two clusters intersect in codimension 1. The associahedron of type `A_n` is one way to realize the classical associahedron as defined in :wikipedia:`Associahedron` A polytopal realization of the associahedron can be found in [CFZ]. The implementation is based on [CFZ, Theorem 1.5, Remark 1.6, and Corollary 1.9.]. EXAMPLES:: sage: Asso = Associahedron(['A',2]); Asso Generalized associahedron of type ['A', 2] with 5 vertices sage: sorted(Asso.Hrepresentation(), key=repr) [An inequality (-1, 0) x + 1 >= 0, An inequality (0, -1) x + 1 >= 0, An inequality (0, 1) x + 1 >= 0, An inequality (1, 0) x + 1 >= 0, An inequality (1, 1) x + 1 >= 0] sage: Asso.Vrepresentation() (A vertex at (1, -1), A vertex at (1, 1), A vertex at (-1, 1), A vertex at (-1, 0), A vertex at (0, -1)) sage: Associahedron(['B',2]) Generalized associahedron of type ['B', 2] with 6 vertices The two pictures of [CFZ] can be recovered with:: sage: Asso = Associahedron(['A',3]); Asso Generalized associahedron of type ['A', 3] with 14 vertices sage: Asso.plot() sage: Asso = Associahedron(['B',3]); Asso Generalized associahedron of type ['B', 3] with 20 vertices sage: Asso.plot() TESTS:: sage: sorted(Associahedron(['A',3]).vertices()) [A vertex at (-3/2, 0, -1/2), A vertex at (-3/2, 0, 3/2), A vertex at (-3/2, 1, -3/2), A vertex at (-3/2, 2, -3/2), A vertex at (-3/2, 2, 3/2), A vertex at (-1/2, -1, -1/2), A vertex at (-1/2, 0, -3/2), A vertex at (1/2, -2, 1/2), A vertex at (1/2, -2, 3/2), A vertex at (3/2, -2, 1/2), A vertex at (3/2, -2, 3/2), A vertex at (3/2, 0, -3/2), A vertex at (3/2, 2, -3/2), A vertex at (3/2, 2, 3/2)] sage: sorted(Associahedron(['B',3]).vertices()) [A vertex at (-3, 0, 0), A vertex at (-3, 0, 3), A vertex at (-3, 2, -2), A vertex at (-3, 4, -3), A vertex at (-3, 5, -3), A vertex at (-3, 5, 3), A vertex at (-2, 1, -2), A vertex at (-2, 3, -3), A vertex at (-1, -2, 0), A vertex at (-1, -1, -1), A vertex at (1, -4, 1), A vertex at (1, -3, 0), A vertex at (2, -5, 2), A vertex at (2, -5, 3), A vertex at (3, -5, 2), A vertex at (3, -5, 3), A vertex at (3, -3, 0), A vertex at (3, 3, -3), A vertex at (3, 5, -3), A vertex at (3, 5, 3)] sage: Associahedron(['A',4]).f_vector() (1, 42, 84, 56, 14, 1) sage: Associahedron(['B',4]).f_vector() (1, 70, 140, 90, 20, 1) REFERENCES: - [CFZ] Chapoton, Fomin, Zelevinsky - Polytopal realizations of generalized associahedra, arXiv:0202004. """ cartan_type = CartanType(cartan_type) parent = Associahedra(QQ, cartan_type.rank()) return parent(cartan_type)
def __classcall_private__(cls, *args, **kwds): """ Normalize input so we can inherit from spare integer matrix. .. NOTE:: To disable the Cartan type check, use the optional argument ``cartan_type_check = False``. EXAMPLES:: sage: C = CartanMatrix(['A',1,1]) sage: C2 = CartanMatrix([[2, -2], [-2, 2]]) sage: C3 = CartanMatrix(matrix([[2, -2], [-2, 2]]), [0, 1]) sage: C == C2 and C == C3 True """ # Special case with 0 args and kwds has cartan type if "cartan_type" in kwds and len(args) == 0: args = (CartanType(kwds["cartan_type"]),) if len(args) == 0: data = [] n = 0 index_set = tuple() cartan_type = None subdivisions = None elif len(args) == 4 and isinstance(args[0], MatrixSpace): # For pickling return typecall(cls, args[0], args[1], args[2], args[3]) elif isinstance(args[0], CartanMatrix): return args[0] else: cartan_type = None dynkin_diagram = None subdivisions = None try: cartan_type = CartanType(args[0]) dynkin_diagram = cartan_type.dynkin_diagram() except (TypeError, ValueError): pass if dynkin_diagram is not None: n = cartan_type.rank() index_set = dynkin_diagram.index_set() reverse = dict((index_set[i], i) for i in range(len(index_set))) data = {(i, i): 2 for i in range(n)} for (i,j,l) in dynkin_diagram.edge_iterator(): data[(reverse[j], reverse[i])] = -l else: M = matrix(args[0]) if not is_generalized_cartan_matrix(M): raise ValueError("The input matrix is not a generalized Cartan matrix.") n = M.ncols() if "cartan_type" in kwds: cartan_type = CartanType(kwds["cartan_type"]) elif n == 1: cartan_type = CartanType(['A', 1]) elif kwds.get("cartan_type_check", True): cartan_type = find_cartan_type_from_matrix(M) data = M.dict() subdivisions = M._subdivisions if len(args) == 1: if cartan_type is not None: index_set = tuple(cartan_type.index_set()) else: index_set = tuple(range(M.ncols())) elif len(args) == 2: index_set = tuple(args[1]) if len(index_set) != n and len(set(index_set)) != n: raise ValueError("The given index set is not valid.") else: raise ValueError("Too many arguments.") mat = typecall(cls, MatrixSpace(ZZ, n, sparse=True), data, cartan_type, index_set) mat._subdivisions = subdivisions return mat
def __classcall_private__(cls, cartan_type, shapes=None, shape=None): """ Normalizes the input arguments to ensure unique representation, and to delegate the construction of spin tableaux. EXAMPLES:: sage: T1 = crystals.Tableaux(CartanType(['A',3]), shape = [2,2]) sage: T2 = crystals.Tableaux(['A',3], shape = (2,2)) sage: T3 = crystals.Tableaux(['A',3], shapes = ([2,2],)) sage: T2 is T1, T3 is T1 (True, True) sage: T1 = crystals.Tableaux(['A', [1,1]], shape=[3,1,1,1]) sage: T1 Crystal of BKK tableaux of shape [3, 1, 1, 1] of gl(2|2) sage: T2 = crystals.Tableaux(['A', [1,1]], [3,1,1,1]) sage: T1 is T2 True """ cartan_type = CartanType(cartan_type) if cartan_type.letter == 'A' and isinstance(cartan_type, SuperCartanType_standard): if shape is None: shape = shapes shape = _Partitions(shape) from sage.combinat.crystals.bkk_crystals import CrystalOfBKKTableaux return CrystalOfBKKTableaux(cartan_type, shape=shape) if cartan_type.letter == 'Q': if any(shape[i] == shape[i + 1] for i in range(len(shape) - 1)): raise ValueError("not a strict partition") shape = _Partitions(shape) return CrystalOfQueerTableaux(cartan_type, shape=shape) n = cartan_type.rank() # standardize shape/shapes input into a tuple of tuples # of length n, or n+1 in type A assert operator.xor(shape is not None, shapes is not None) if shape is not None: shapes = (shape, ) if cartan_type.type() == "A": n1 = n + 1 else: n1 = n if not all(all(i == 0 for i in shape[n1:]) for shape in shapes): raise ValueError( "shapes should all have length at most equal to the rank or the rank + 1 in type A" ) spin_shapes = tuple((tuple(shape) + (0, ) * (n1 - len(shape)))[:n1] for shape in shapes) try: shapes = tuple( tuple(trunc(i) for i in shape) for shape in spin_shapes) except Exception: raise ValueError( "shapes should all be partitions or half-integer partitions") if spin_shapes == shapes: shapes = tuple( _Partitions(shape) if shape[n1 - 1] in NN else shape for shape in shapes) return super(CrystalOfTableaux, cls).__classcall__(cls, cartan_type, shapes) # Handle the construction of a crystals of spin tableaux # Caveat: this currently only supports all shapes being half # integer partitions of length the rank for type B and D. In # particular, for type D, the spins all have to be plus or all # minus spins if any(len(sh) != n for sh in shapes): raise ValueError( "the length of all half-integer partition shapes should be the rank" ) if any(2 * i % 2 != 1 for shape in spin_shapes for i in shape): raise ValueError( "shapes should be either all partitions or all half-integer partitions" ) if any( any(i < j for i, j in zip(shape, shape[1:-1] + (abs(shape[-1]), ))) for shape in spin_shapes): raise ValueError("entries of each shape must be weakly decreasing") if cartan_type.type() == 'D': if all(i >= 0 for shape in spin_shapes for i in shape): S = CrystalOfSpinsPlus(cartan_type) elif all(shape[-1] < 0 for shape in spin_shapes): S = CrystalOfSpinsMinus(cartan_type) else: raise ValueError( "in type D spins should all be positive or negative") else: if any(i < 0 for shape in spin_shapes for i in shape): raise ValueError("shapes should all be partitions") S = CrystalOfSpins(cartan_type) B = CrystalOfTableaux(cartan_type, shapes=shapes) T = TensorProductOfCrystals(S, B, generators=[[S.module_generators[0], x] for x in B.module_generators]) T.rename("The crystal of tableaux of type %s and shape(s) %s" % (cartan_type, list(list(shape) for shape in spin_shapes))) T.shapes = spin_shapes return T
def Shi(self, data, K=QQ, names=None, m=1): r""" Return the Shi arrangement. INPUT: - ``data`` -- either an integer or a Cartan type (or coercible into; see "CartanType") - ``K`` -- field (default:``QQ``) - ``names`` -- tuple of strings or ``None`` (default); the variable names for the ambient space - ``m`` -- integer (default: 1) OUTPUT: - If ``data`` is an integer `n`, return the Shi arrangement in dimension `n`, i.e. the set of `n(n-1)` hyperplanes: `\{ x_i - x_j = 0,1 : 1 \leq i \leq j \leq n \}`. This corresponds to the Shi arrangement of Cartan type `A_{n-1}`. - If ``data`` is a Cartan type, return the Shi arrangement of given type. - If `m > 1`, return the `m`-extended Shi arrangement of given type. The `m`-extended Shi arrangement of a given crystallographic Cartan type is defined by the inner product `\langle a,x \rangle = k` for `-m < k \leq m` and `a \in \Phi^+` is a positive root of the root system `\Phi`. EXAMPLES:: sage: hyperplane_arrangements.Shi(4) Arrangement of 12 hyperplanes of dimension 4 and rank 3 sage: hyperplane_arrangements.Shi("A3") Arrangement of 12 hyperplanes of dimension 4 and rank 3 sage: hyperplane_arrangements.Shi("A3",m=2) Arrangement of 24 hyperplanes of dimension 4 and rank 3 sage: hyperplane_arrangements.Shi("B4") Arrangement of 32 hyperplanes of dimension 4 and rank 4 sage: hyperplane_arrangements.Shi("B4",m=3) Arrangement of 96 hyperplanes of dimension 4 and rank 4 sage: hyperplane_arrangements.Shi("C3") Arrangement of 18 hyperplanes of dimension 3 and rank 3 sage: hyperplane_arrangements.Shi("D4",m=3) Arrangement of 72 hyperplanes of dimension 4 and rank 4 sage: hyperplane_arrangements.Shi("E6") Arrangement of 72 hyperplanes of dimension 8 and rank 6 sage: hyperplane_arrangements.Shi("E6",m=2) Arrangement of 144 hyperplanes of dimension 8 and rank 6 If the Cartan type is not crystallographic, the Shi arrangement is not defined:: sage: hyperplane_arrangements.Shi("H4") Traceback (most recent call last): ... NotImplementedError: Shi arrangements are not defined for non crystallographic Cartan types The characteristic polynomial is pre-computed using the results of [Ath1996]_:: sage: hyperplane_arrangements.Shi("A3").characteristic_polynomial() x^4 - 12*x^3 + 48*x^2 - 64*x sage: hyperplane_arrangements.Shi("A3",m=2).characteristic_polynomial() x^4 - 24*x^3 + 192*x^2 - 512*x sage: hyperplane_arrangements.Shi("C3").characteristic_polynomial() x^3 - 18*x^2 + 108*x - 216 sage: hyperplane_arrangements.Shi("E6").characteristic_polynomial() x^8 - 72*x^7 + 2160*x^6 - 34560*x^5 + 311040*x^4 - 1492992*x^3 + 2985984*x^2 sage: hyperplane_arrangements.Shi("B4",m=3).characteristic_polynomial() x^4 - 96*x^3 + 3456*x^2 - 55296*x + 331776 TESTS:: sage: h = hyperplane_arrangements.Shi(4) sage: h.characteristic_polynomial() x^4 - 12*x^3 + 48*x^2 - 64*x sage: h.characteristic_polynomial.clear_cache() # long time sage: h.characteristic_polynomial() # long time x^4 - 12*x^3 + 48*x^2 - 64*x sage: h = hyperplane_arrangements.Shi("A3",m=2) sage: h.characteristic_polynomial() x^4 - 24*x^3 + 192*x^2 - 512*x sage: h.characteristic_polynomial.clear_cache() sage: h.characteristic_polynomial() x^4 - 24*x^3 + 192*x^2 - 512*x sage: h = hyperplane_arrangements.Shi("B3",m=3) sage: h.characteristic_polynomial() x^3 - 54*x^2 + 972*x - 5832 sage: h.characteristic_polynomial.clear_cache() sage: h.characteristic_polynomial() x^3 - 54*x^2 + 972*x - 5832 """ if data in NN: cartan_type = CartanType(["A", data - 1]) else: cartan_type = CartanType(data) if not cartan_type.is_crystallographic(): raise NotImplementedError( "Shi arrangements are not defined for non crystallographic Cartan types" ) n = cartan_type.rank() h = cartan_type.coxeter_number() Ra = RootSystem(cartan_type).ambient_space() PR = Ra.positive_roots() d = Ra.dimension() H = make_parent(K, d, names) x = H.gens() hyperplanes = [] for a in PR: for const in range(-m + 1, m + 1): hyperplanes.append(sum(a[j] * x[j] for j in range(d)) - const) A = H(*hyperplanes) x = polygen(QQ, 'x') charpoly = x**(d - n) * (x - m * h)**n A.characteristic_polynomial.set_cache(charpoly) return A
def Associahedron(cartan_type): r""" Construct an associahedron. The generalized associahedron is a polytopal complex with vertices in one-to-one correspondence with clusters in the cluster complex, and with edges between two vertices if and only if the associated two clusters intersect in codimension 1. The associahedron of type `A_n` is one way to realize the classical associahedron as defined in the :wikipedia:`Associahedron`. A polytopal realization of the associahedron can be found in [CFZ]_. The implementation is based on [CFZ]_, Theorem 1.5, Remark 1.6, and Corollary 1.9. EXAMPLES:: sage: Asso = polytopes.associahedron(['A',2]); Asso Generalized associahedron of type ['A', 2] with 5 vertices sage: sorted(Asso.Hrepresentation(), key=repr) [An inequality (-1, 0) x + 1 >= 0, An inequality (0, -1) x + 1 >= 0, An inequality (0, 1) x + 1 >= 0, An inequality (1, 0) x + 1 >= 0, An inequality (1, 1) x + 1 >= 0] sage: Asso.Vrepresentation() (A vertex at (1, -1), A vertex at (1, 1), A vertex at (-1, 1), A vertex at (-1, 0), A vertex at (0, -1)) sage: polytopes.associahedron(['B',2]) Generalized associahedron of type ['B', 2] with 6 vertices The two pictures of [CFZ]_ can be recovered with:: sage: Asso = polytopes.associahedron(['A',3]); Asso Generalized associahedron of type ['A', 3] with 14 vertices sage: Asso.plot() Graphics3d Object sage: Asso = polytopes.associahedron(['B',3]); Asso Generalized associahedron of type ['B', 3] with 20 vertices sage: Asso.plot() Graphics3d Object TESTS:: sage: sorted(polytopes.associahedron(['A',3]).vertices()) [A vertex at (-3/2, 0, -1/2), A vertex at (-3/2, 0, 3/2), A vertex at (-3/2, 1, -3/2), A vertex at (-3/2, 2, -3/2), A vertex at (-3/2, 2, 3/2), A vertex at (-1/2, -1, -1/2), A vertex at (-1/2, 0, -3/2), A vertex at (1/2, -2, 1/2), A vertex at (1/2, -2, 3/2), A vertex at (3/2, -2, 1/2), A vertex at (3/2, -2, 3/2), A vertex at (3/2, 0, -3/2), A vertex at (3/2, 2, -3/2), A vertex at (3/2, 2, 3/2)] sage: sorted(polytopes.associahedron(['B',3]).vertices()) [A vertex at (-3, 0, 0), A vertex at (-3, 0, 3), A vertex at (-3, 2, -2), A vertex at (-3, 4, -3), A vertex at (-3, 5, -3), A vertex at (-3, 5, 3), A vertex at (-2, 1, -2), A vertex at (-2, 3, -3), A vertex at (-1, -2, 0), A vertex at (-1, -1, -1), A vertex at (1, -4, 1), A vertex at (1, -3, 0), A vertex at (2, -5, 2), A vertex at (2, -5, 3), A vertex at (3, -5, 2), A vertex at (3, -5, 3), A vertex at (3, -3, 0), A vertex at (3, 3, -3), A vertex at (3, 5, -3), A vertex at (3, 5, 3)] sage: polytopes.associahedron(['A',4]).f_vector() (1, 42, 84, 56, 14, 1) sage: polytopes.associahedron(['B',4]).f_vector() (1, 70, 140, 90, 20, 1) """ cartan_type = CartanType(cartan_type) parent = Associahedra(QQ, cartan_type.rank()) return parent(cartan_type)
def __classcall_private__(cls, *args, **kwds): """ Normalize input so we can inherit from spare integer matrix. .. NOTE:: To disable the Cartan type check, use the optional argument ``cartan_type_check = False``. EXAMPLES:: sage: C = CartanMatrix(['A',1,1]) sage: C2 = CartanMatrix([[2, -2], [-2, 2]]) sage: C3 = CartanMatrix(matrix([[2, -2], [-2, 2]]), [0, 1]) sage: C == C2 and C == C3 True """ # Special case with 0 args and kwds has cartan type if "cartan_type" in kwds and len(args) == 0: args = (CartanType(kwds["cartan_type"]), ) if len(args) == 0: data = [] n = 0 index_set = tuple() cartan_type = None subdivisions = None elif len(args) == 4 and isinstance(args[0], MatrixSpace): # For pickling return typecall(cls, args[0], args[1], args[2], args[3]) elif isinstance(args[0], CartanMatrix): return args[0] else: cartan_type = None dynkin_diagram = None subdivisions = None try: cartan_type = CartanType(args[0]) dynkin_diagram = cartan_type.dynkin_diagram() except (TypeError, ValueError): pass if dynkin_diagram is not None: n = cartan_type.rank() index_set = dynkin_diagram.index_set() reverse = dict( (index_set[i], i) for i in range(len(index_set))) data = {(i, i): 2 for i in range(n)} for (i, j, l) in dynkin_diagram.edge_iterator(): data[(reverse[j], reverse[i])] = -l else: M = matrix(args[0]) if not is_generalized_cartan_matrix(M): raise ValueError( "The input matrix is not a generalized Cartan matrix.") n = M.ncols() if "cartan_type" in kwds: cartan_type = CartanType(kwds["cartan_type"]) elif n == 1: cartan_type = CartanType(['A', 1]) elif kwds.get("cartan_type_check", True): cartan_type = find_cartan_type_from_matrix(M) data = M.dict() subdivisions = M._subdivisions if len(args) == 1: if cartan_type is not None: index_set = tuple(cartan_type.index_set()) else: index_set = tuple(range(M.ncols())) elif len(args) == 2: index_set = tuple(args[1]) if len(index_set) != n and len(set(index_set)) != n: raise ValueError("The given index set is not valid.") else: raise ValueError("Too many arguments.") mat = typecall(cls, MatrixSpace(ZZ, n, sparse=True), data, cartan_type, index_set) mat._subdivisions = subdivisions return mat