Path: blob/master/sage/geometry/toric_lattice_element.pyx
4096 views
r"""1Toric lattice elements23This module was designed as a part of the framework for toric varieties4(:mod:`~sage.schemes.toric.variety`,5:mod:`~sage.schemes.toric.fano_variety`).67AUTHORS:89- Andrey Novoseltsev (2010-05-27): initial version.1011TESTS:1213Let's create some lattices first::1415sage: N = ToricLattice(3)16sage: M = N.dual()1718Now we are ready to create elements of toric lattices::1920sage: n = N([1,2,3])21sage: n22N(1, 2, 3)23sage: m = M(1,2,3)24sage: m25M(1, 2, 3)2627Dual lattices can act on each other::2829sage: n * m301431sage: m * n32143334You can also add elements of the same lattice or scale them::3536sage: 2 * n37N(2, 4, 6)38sage: n * 239N(2, 4, 6)40sage: n + n41N(2, 4, 6)4243However, you cannot "mix wrong lattices" in your expressions::4445sage: n + m46Traceback (most recent call last):47...48TypeError: unsupported operand parent(s) for '+':49'3-d lattice N' and '3-d lattice M'50sage: n * n51Traceback (most recent call last):52...53TypeError: elements of the same toric lattice cannot be multiplied!54sage: n == m55False5657Note that ``n`` and ``m`` are not equal to each other even though they are58both "just (1,2,3)." Moreover, you cannot easily convert elements between59toric lattices::6061sage: M(n)62Traceback (most recent call last):63...64TypeError: N(1, 2, 3) cannot be converted to 3-d lattice M!6566If you really need to consider elements of one lattice as elements of another,67you can either use intermediate conversion to "just a vector"::6869sage: ZZ3 = ZZ^370sage: n_in_M = M(ZZ3(n))71sage: n_in_M72M(1, 2, 3)73sage: n == n_in_M74False75sage: n_in_M == m76True7778Or you can create a homomorphism from one lattice to any other::7980sage: h = N.hom(identity_matrix(3), M)81sage: h(n)82M(1, 2, 3)83"""84# The "tutorial" above is a truncated version of one in toric_lattice.py.858687#*****************************************************************************88# Copyright (C) 2010 Andrey Novoseltsev <[email protected]>89# Copyright (C) 2010 William Stein <[email protected]>90#91# Distributed under the terms of the GNU General Public License (GPL)92#93# http://www.gnu.org/licenses/94#*****************************************************************************959697include '../ext/cdefs.pxi'98include '../ext/stdsage.pxi' # Needed for PY_NEW99100from sage.geometry.toric_plotter import ToricPlotter101from sage.modules.vector_integer_dense cimport Vector_integer_dense102from sage.structure.coerce_exceptions import CoercionException103from sage.structure.element cimport Element, Vector104from sage.rings.integer cimport Integer105106107def is_ToricLatticeElement(x):108r"""109Check if ``x`` is an element of a toric lattice.110111INPUT:112113- ``x`` -- anything.114115OUTPUT:116117- ``True`` if ``x`` is an element of a toric lattice, ``False`` otherwise.118119EXAMPLES::120121sage: from sage.geometry.toric_lattice_element import (122... is_ToricLatticeElement)123sage: is_ToricLatticeElement(1)124False125sage: e = ToricLattice(3).an_element()126sage: e127N(1, 0, 0)128sage: is_ToricLatticeElement(e)129True130"""131return isinstance(x, ToricLatticeElement)132133134# Why do we need a special class:135# - customize output to include lattice name136# - prohibit operations mixing "wrong" lattices137cdef class ToricLatticeElement(Vector_integer_dense):138r"""139Create an element of a toric lattice.140141.. WARNING::142143You probably should not construct such elements explicitly.144145INPUT:146147- same as for148:class:`~sage.modules.vector_integer_dense.Vector_integer_dense`.149150OUTPUT:151152- element of a toric lattice.153154TESTS::155156sage: N = ToricLattice(3)157sage: from sage.geometry.toric_lattice_element import (158... ToricLatticeElement)159sage: e = ToricLatticeElement(N, [1,2,3])160sage: e161N(1, 2, 3)162sage: TestSuite(e).run()163"""164165# We do not add any new functionality, we actually limit the existing one166# instead. In particular, there is no need in __init__, but the following167# function ensures that _add_ etc. return ToricLatticeElement, rather168# than Vector_integer_dense. Its code is copied from the base class with169# the type name replacements.170# It is not detected by doctest coverage, the original has no171# documentation, and I don't feel I can clearly define the exact part of172# the initialization process which is done by it. So I will leave it173# without any further documentation as well...174cdef _new_c(self):175cdef ToricLatticeElement y176y = PY_NEW(ToricLatticeElement)177y._init(self._degree, self._parent)178return y179180def __cmp__(self, right):181r"""182Compare ``self`` and ``right``.183184INPUT:185186- ``right`` -- anything.187188OUTPUT:189190- 0 if ``right`` is an equal element of the same toric lattice as191``self``, 1 or -1 otherwise.192193TESTS::194195sage: N = ToricLattice(3)196sage: M = N.dual()197sage: n = N(1,2,3)198sage: m = M(1,2,3)199sage: cmp(n, m)2001201sage: n2 = N(1,2,3)202sage: cmp(n, n2)2030204sage: n is n2205False206sage: n == 1207False208"""209c = cmp(type(self), type(right))210PL = self.parent()211PR = right.parent()212try:213c = cmp(PL.ambient_module(), PR.ambient_module())214if c:215return c216except AttributeError:217return cmp(PL, PR)218# Now use the real comparison of vectors219return self._cmp_c_impl(right)220221# For some reason, vectors work just fine without redefining this function222# from the base class, but if it is not here, we get "unhashable type"...223def __hash__(self):224r"""225Return the hash of ``self``.226227OUTPUT:228229- integer.230231TESTS::232233sage: N = ToricLattice(3)234sage: n = N(1,2,3)235sage: hash(n)236Traceback (most recent call last):237...238TypeError: mutable vectors are unhashable239sage: n.set_immutable()240sage: hash(n) == hash(n)241True242"""243return Vector_integer_dense.__hash__(self)244245cpdef _act_on_(self, other, bint self_on_left):246"""247Act on ``other``.248249INPUT:250251- ``other`` - :class:`ToricLatticeElement`.252253OUTPUT:254255- integer, if ``other`` is an element of the dual lattice of ``self``;256257- ``CoercionException`` is raised if ``other`` is an element of258an incompatible toric lattice;259260- standard output for ``self`` acting as an integral vector on261``other`` if the latter one is not an element of a toric lattice.262263TESTS::264265sage: N = ToricLattice(3)266sage: M = N.dual()267sage: n = N(1,2,3)268sage: m = M(1,2,3)269sage: n * m # indirect doctest27014271272Now we test behaviour with other types::273274sage: v = vector([1, 2, 3])275sage: v * n == n * v276True277sage: v = vector([1, 1/2, 3/4])278sage: v * n == n * v279True280sage: A = matrix(3, range(9))281sage: A * n282(8, 26, 44)283sage: n * A284(24, 30, 36)285sage: B = A / 3286sage: B * n287(8/3, 26/3, 44/3)288sage: n * B289(8, 10, 12)290"""291Ns = self.parent()292# We try to deal only with the case of two lattice elements...293if is_ToricLatticeElement(other):294if other.parent().ambient_module() is Ns.ambient_module().dual():295# Our own _dot_product_ is disabled296return Vector_integer_dense._dot_product_(self, other)297raise CoercionException("only elements of dual toric lattices "298"can act on each other!")299# ... however we also need to treat the case when other is an integral300# vector, since otherwise it will be coerced to the parent of self and301# then the dot product will be called for elements of the same lattice302if isinstance(other, Vector_integer_dense):303return Vector_integer_dense._dot_product_(self, other)304# We also allow action on elements of lattice quotients305try:306lift = other.lift()307if is_ToricLatticeElement(lift):308if other.parent().W().is_submodule(Ns.dual().W()):309return Vector_integer_dense._dot_product_(self, lift)310raise CoercionException("only elements of dual toric lattices "311"can act on each other!")312except AttributeError: # No lift313pass314# Now let the standard framework work...315return Vector_integer_dense._act_on_(self, other, self_on_left)316317# We need to override this function to prohibit default behaviour.318# It seems to be called when right is in the same lattice as self, which319# is wrong from our point of view.320cpdef Element _dot_product_(self, Vector right):321"""322Raise a ``TypeError`` exception.323324Dot product is not defined on toric lattices (there are actions of325dual lattices on each other instead).326327INPUT:328329- ``right`` - vector.330331OUTPUT:332333- ``TypeError`` exception is raised.334335TESTS::336337sage: N = ToricLattice(3)338sage: M = N.dual()339sage: n = N(1,2,3)340sage: m = M(1,2,3)341sage: n * n # indirect doctest342Traceback (most recent call last):343...344TypeError: elements of the same345toric lattice cannot be multiplied!346"""347raise TypeError("elements of the same toric lattice cannot be "348"multiplied!")349350def _latex_(self):351r"""352Return a LaTeX representation of ``self``.353354OUTPUT:355356- string.357358TESTS::359360sage: Ld = ToricLattice(3, "L").dual()361sage: e = Ld(1,2,3)362sage: e._latex_()363'\\left(1,\\,2,\\,3\\right)_{L^*}'364"""365return "%s_{%s}" % (super(ToricLatticeElement, self)._latex_(),366self.parent().ambient_module()._latex_name)367368def _repr_(self):369r"""370Return a string representation of ``self``.371372OUTPUT:373374- string.375376TESTS::377378sage: Ld = ToricLattice(3, "L").dual()379sage: e = Ld(1,2,3)380sage: e._repr_()381'L*(1, 2, 3)'382"""383return (self.parent().ambient_module()._name384+ super(ToricLatticeElement, self)._repr_())385386def __reduce__(self):387"""388Override the base ``__reduce__`` to correctly pickle/unpickle elements.389390EXAMPLES::391392sage: N = ToricLattice(3)393sage: loads(dumps(N(1,2,3)))394N(1, 2, 3)395"""396return (unpickle_v1, (self._parent, self.list(), self._degree, self._is_mutable))397398def plot(self, **options):399r"""400Plot ``self``.401402INPUT:403404- any options for toric plots (see :func:`toric_plotter.options405<sage.geometry.toric_plotter.options>`), none are mandatory.406407OUTPUT:408409- a plot.410411EXAMPLES::412413sage: N = ToricLattice(3)414sage: n = N(1,2,3)415sage: n.plot()416"""417tp = ToricPlotter(options, self.parent().degree())418tp.adjust_options()419return tp.plot_points([self])420421422def unpickle_v1(parent, entries, degree, is_mutable):423"""424Unpickle a :class:`ToricLatticeElement`425426INPUT:427428- ``parent`` -- The parent toric lattice.429430- ``entries`` -- a list. The coordinates of the lattice point.431432- ``degree`` -- integer. the dimension of the toric lattice.433434- ``is_mutable`` -- boolean. Whether the lattice element is435mutable.436437OUTPUT:438439The :class:`ToricLatticeElement` determined by the input data.440441EXAMPLES::442443sage: N = ToricLattice(3, "lattice")444sage: loads(dumps(N(1,2,3))) # indirect test445lattice(1, 2, 3)446sage: from sage.geometry.toric_lattice_element import unpickle_v1447sage: unpickle_v1(N,[1,2,3],3,True)448lattice(1, 2, 3)449"""450cdef ToricLatticeElement v451v = PY_NEW(ToricLatticeElement)452v._init(degree, parent)453cdef Integer z454for i from 0 <= i < degree:455z = Integer(entries[i])456mpz_init_set(v._entries[i], z.value)457v._is_mutable = is_mutable458return v459460461