Polymake Template Library (PTL): Container Manipulations
Polymake Template Library (PTL)  4.2
Container Manipulations

All constructions described on this page are similar in that they take one or more objects and produce a new object which behaves like a container, too. However, in all these cases it is not a container in the strict sense: it does not own any data. We will call them pseudo-container throughout this documentation.

The pseudo-containers can be divided in three categories according to their functionality:

  • An alias pseudo-container forwards all element access operation to the original data container(s). It can hide some elements away or let them appear in other order, in any case its elements are at the same times elements of the original container. This implies that assigning new values to the elements of a mutable alias container in fact changes the elements in the original container. }
  • A lazy pseudo-container computes its elements on the fly, just at the moment they are accessed to. Thus the elements are temporary objects returned by container access methods (front(), back(), or operator[]) or reside in the iterator. Traversing a lazy container object multiple times object incurs repeating computations, which should be kept in mind when sticking it into a multi-pass algorithm template.

When you write an algorithm template, you can make it safe from multiple evaluation of lazy objects using the following construction:

   typename <Object>::type X=prevent_lazy<Object>::get(x);

where x is an input parameter and Object its type. If Object is really lazy, it performs the evaluation exactly once and stores the results in an appropriate persistent object; if not, it does nothing.

  • A masquerade pseudo-container is just another view on the original object. Unlike the first two kinds, masquerade objects are never created: the original object address is reinterpreted instead; they even can't be created, since their constructors and destructors are purposely declared protected and left undefined.

To make the classification complete, let's call the standard containers, whose lifetime is the same as of their elements, persistent. This notion is traditionally used in the context of data base query languages, where it describes objects that can outlive the programs creating them. This is also applicable to objects in Polymake Template Library, since they can be stored in and retrieved from the a data file via the client communication interface without any loss in structure or contents.

Reference or copy?

For instantiable pseudo-containers (alias and lazy) it is important to know how to find the original data containers. Generally, the latter have a lifetime much longer than a pseudo-container object, which in the most cases exists during exactly one expression. Thus an internal reference to the original object would be sufficient.

On the other hand, the pseudo-containers are easy to combine and nest (it was, after all, the main design aim to made them interchangeable building blocks!) For example, one can first select a subset of elements and then apply an operation to it. In this case, the first operand of the outer pseudo-container will be the inner pseudo-container, which in its turn is a temporary object. It doesn't create a problem until the entire construction is copied outside the scope the components are confined to.

The best example is a return statement: if a function has to return the outer pseudo-container object, it may not contain a reference to the inner object, since it was created in the function's scope and will be destroyed after the return completion. Therefore the inner object must be copied into the outer object.

All pseudo-container objects in the Polymake Template Library can be configured for both scenarios. The template parameters describing the data sources are optional references: they can be specified as references as well as reference-free data types. Note that the convenience functions always create pseudo-containers with internal references, as a more efficient and more often occuring variant; the referenceless variant should be used only when it's really necessary, like in the return context explained above.