Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

answered 0 years ago

dan_fulea gravatar image

For me it is not clear why the simple and direct code that avoids an avatar of a new class is not good enough, so it is hard to design a good class, that makes next steps easy to work. The passage about "diluting a precious namespace" is not really an issue from a pragmatical point of view. The namespace is "something else" while writing code.

The line polytopes.depleted_cube(6).strange_facet().vertices()must be an orientation wish. So let us see what can be realized from it. What is polytopes? I will use p as a short cut.

sage: p = polytopes
sage: print(p)
<sage.geometry.polyhedron.library.Polytopes object at 0x7b0addf97e00>
sage: type(p)
<class 'sage.geometry.polyhedron.library.Polytopes'>

So this is a class. It has many methods. For instance:

sage: p.__init__
<method-wrapper '__init__' of Polytopes object at 0x7b0addf97e00>

And also a lot of other published methods. We avoid the "privat" ones, those starting with an underscore (at least), and pick only the first ten:

sage: [met for met in dir(p) if not met.startswith('_')][:10]
['Birkhoff_polytope',
 'Gosset_3_21',
 'Kirkman_icosahedron',
 'associahedron',
 'bitruncated_six_hundred_cell',
 'buckyball',
 'cantellated_one_hundred_twenty_cell',
 'cantellated_six_hundred_cell',
 'cantitruncated_one_hundred_twenty_cell',
 'cantitruncated_six_hundred_cell']
sage:

(Remove the slicing [:10] to see all of them.) Of course, depleted_cube is not on the list, but we have for instance the h-starting methods:

sage: [met for met in dir(p) if met.startswith('h')]
['hypercube', 'hypersimplex']

So what is polytopes.hypercube?

sage: type(p.hypercube)
<class 'method'>

It is a method. This method returns an object of an other class. So we jump from place to place. What does it return? To get the related code of the method we type:

sage: p.hypercube??

and scroll down. The last lines are:

        return parent([cp, [], []], [ieqs, []], convert=convert, Vrep_minimal=True, Hrep_minimal=True, pref_rep='Hrep')
File:      /usr/lib/python3.13/site-packages/sage/geometry/polyhedron/library.py
Type:      method

We see where the code lives, and what it returns (in some if-case). The involved variables are defined in advance, for instance:

        parent = Polyhedra(ZZ, dim, backend=backend)

But this "thing", parent, is what kind of an object? We must know where we are, when using it, and how to make from a file path the right python object:

sage: my_parent = sage.geometry.polyhedron.library
sage: my_parent.Polyhedra
<function Polyhedra at 0x7b0ade0ca480>

So Polyhedra is a function published in the same py-module. It is not a class, it returns an object, and this object is used in the next construction. (So trying to do "the same" means to define a function - not a class - depleted_cube in the same framework. Why should we inherit a "kind-of-a-factory" class, to have an other such class with a new function, when we can define this function in a direct manner?) Then for instance p.hypercube(3) returns an object.

An object of which class?

sage: C = p.hypercube(3)
sage: type(C)
<class 'sage.geometry.polyhedron.parent.Polyhedra_ZZ_ppl_with_category.element_class'>

Do we really want to inherit from such a "thing". To better get the story of the thing, let us ask:

sage: type(sage)
<class 'module'>
sage: type(sage.geometry)
<class 'module'>
sage: type(sage.geometry.polyhedron)
<class 'module'>
sage: type(sage.geometry.polyhedron.parent)
<class 'module'>
sage: type(sage.geometry.polyhedron.parent.Polyhedra_ZZ_ppl_with_category)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[82], line 1
----> 1 type(sage.geometry.polyhedron.parent.Polyhedra_ZZ_ppl_with_category)

AttributeError: module 'sage.geometry.polyhedron.parent' has no attribute 'Polyhedra_ZZ_ppl_with_category'
sage:

At this point my wish to trace back the places finally and inherit a class is vanishing. There is no reason to search for such a hidden class or function. In fact, a doc string tells us:

def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, *,
              ambient_space=None, base_ring=None):
    r"""
    Construct a suitable parent class for polyhedra.

    INPUT:

    - ``base_ring`` -- a ring; currently there are backends for `\ZZ`,
      `\QQ`, and `\RDF`

    - ``ambient_dim`` -- integer; the ambient space dimension

    - ``ambient_space`` -- a free module

    - ``backend`` -- string. The name of the backend for computations. There are
      several backends implemented:

        * ``backend="ppl"`` uses the Parma Polyhedra Library

        * ``backend="cdd"`` uses CDD

        * ``backend="normaliz"`` uses normaliz

        * ``backend="polymake"`` uses polymake

        * ``backend="field"`` a generic Sage implementation

    OUTPUT:

    A parent class for polyhedra over the given base ring if the
    backend supports it. If not, the parent base ring can be larger
    (for example, `\QQ` instead of `\ZZ`). If there is no
    implementation at all, a :exc:`ValueError` is raised.

So Polyhedra is a function returning a class. (Which has its constructor, some methods, and so on.) In other words, the libraries are constructing first a dual, advanced world, then from this world the final geometric objects in suitable dimensions over suitable rings. As an user of the library, it is not easy and/or it does not make sense to extend a package outside of the package. (Since it may change, thus thing stop to work or to be maintainable.)