<operations.h>
It is automatically included together with all top-level data structures.
<ContainerChain.h>
It is automatically included together with all top-level data structures.
<IndexedSubset.h>
It is automatically included together with all top-level data structures.
<assoc.h>
It is automatically included together with all associative containers (Map,
SparseVector, IncidenceMatrix, etc).
<normalize.h>
<comparators.h>
It is automatically included together with all top-level data structures.
| class | polymorphic operator or function | semantics besides the built-in operators |
|---|---|---|
operations::neg |
-X |
arithmetic negation (vector, matrix) |
operations::add |
X+Y |
addition (vector, matrix,) set union |
operations::sub |
X-Y |
subtraction (vector, matrix,) set difference |
operations::mul |
X*Y |
multiplication (all combinations of scalars, vectors, and matrices,) set intersection |
operations::square |
sqr(X) |
product of scalar, vector, or matrix with itself |
operations::normalize |
X/=sqrt(sqr(X)) |
normalize a vector with floating-point coordinates |
operations::tensor |
tensor_product(X,Y) |
tensor product of vectors |
operations::div |
X/Y |
division (vector or matrix thru scalar), matrix rowwise concatenation |
operations::mod |
X%Y |
- |
operations::bitwise_not |
~X |
set complement |
operations::bitwise_or |
X|Y |
vector and matrix columnwise concatenation |
operations::bitwise_and |
X&Y |
- |
operations::bitwise_xor |
X^Y |
symmetric set difference |
operations::cmp |
X<=>Y (in Perl) |
compare objects arithmetically (scalar) or lexicographically (container), returning
cmp_value.
This functor (and other functionally interchangeable with it) is called thru this documentation
a comparator. It can be expected to work more efficiently than two subsequent comparisons
X<Y; X>Y as practiced in STL code.
|
operations::positive |
X>0 |
- |
operations::negative |
X<0 |
- |
operations::zero |
X==0 |
The specialization for double can be constructed with an epsilon argument.
All numbers such that abs(x)<=epsilon are mapped to true.
Default value for epsilon is 10-8. |
operations::eq |
X==Y |
All comparison operators are based on cmp.
Therefore it is necessary to specialize only the latter for each new data type.
|
operations::ne |
X!=Y |
|
operations::lt |
X<Y |
|
operations::le |
X<=Y |
|
operations::gt |
X>Y |
|
operations::ge |
X>=Y |
|
operations::max |
std::max(X,Y) |
|
operations::min |
std::min(X,Y) |
|
operations::clear |
X() |
construct an object with its default container; reset an object to the default state (assignment version) |
operations::concat |
concatenate(X,Y) |
concatenation (container, vector, matrix - columnwise) |
operations::slice |
- | select a subset (vector slice) using given element indices |
operations::associative |
X[Y] |
find an element in an associative container (map) |
Functors are classes with special interface defined in
STL. Briefly resembling,
one functor class encodes a single operation, defined as operator(). Furthermore it
must declare the type of the operation result as result_type and the types of the
input parameter(s) as argument_type in case of a unary operation or
as first_argument_type and second_argument_type in the binary case.
Functors in Polymake Template Library obey the same rules, but with slight modifications:
In STL, all the typedef's mentioned above always refer to unqualified data types.
Polymake functor may define them also as references and/or with const
attribute:
operator(), with const and reference
attributes if needed.
operator() be always a lvalue with suitable const
qualification (that is, no temporary objects allowed.)
If an operation has an assignment version (such as X+=Y), it is also accessible
in the functor class as
They always return the reference to their first argument, as the built-in assigment operators do.
When performing a binary operation on elements of sparse containers (vectors, matrices, ...), it is useful to explicitly define the result in the situation when one operand is an implicitly given "zero". (It is much more efficient than creating a temporary zero and computing the result with the standard binary operator.)
If the functor takes no precautions on this, the result is assumed to be zero too, and the
computation is skipped at all. This is OK for multiplication or bitwise "and",
but not for addition or concatenation. The functors like the latter overload the operator()
with specializations looking like:
partial_left and partial_right are empty tag classes and must
be written verbatim.
Iterator arguments point to the next explicit element in the sparse container
(that is, after the gap); they can be safely ignored in the most cases.
All functors defined in namespace pm::operations
are class templates parameterized with types of input argument(s). In the most cases, these types
can be automatically deduced from the context, which makes the explicit specification superfluous.
(Moreover, in a nested expression involving function and class templates,
it is not always easy to guess the input argument type right!)
Unfortunately, the syntax rules of C++ do not allow to intermix classes with "naked" templates. Therefore there are two special classes introduced with the only aim to wrap the parameterless template:
In the most constructions taking a functor class as a class template parameter or function argument,
it can be specified either as a normal class or as a functor template wrapped in
BuildUnary or BuildBinary. Example:
and
are effectively identical: both compute the sum of all vector elements.
The shortcuts defined in the namespace polymake::operations help to make the application code
still more concise. The expression above can be equivalently rewritten as:
If the advantage of the "naked" functor templates seems to you as not too much essential, try to sum the rows of a matrix without using them.
In some special cases it is more convenient to pass an iterator to the functor instead of data items it is pointing to. Most often such functors are used in pseudo-containers. There are three possibilities to build a functor with this kind of interface:
argument_type, etc. as the exact iterator type the functor
expects.
argument_type as void and write the operator() as a
member template parameterized with input iterator type(s).
Whatever design you choose, this special interface will be automatically recognized in all pseudo-container classes and basic algorithms.
A functor encoding an operation overloaded for various input types must be specialized for each input type (or pair in the binary case) that yields a different result type. If you need to define your own overloaded functors, you can use the discriminant mechanism shown in the following examples:
template <typename OpRef,
typename Discr=typename object_traits<typename deref<OpRef>::type>::generic_tag>
struct neg_impl;
The first parameter is an input operand type; it can happen to be a reference
(especially when instantiated via BuildUnary), therefore the pure
data type must be first distilled using deref. generic_tag
can take one of following types (the list is not exhausting):
GenericSet
GenericVector
GenericMatrix
GenericIncidenceMatrix
template <typename LeftRef, typename RightRef, bool check=false,
typename Discr=typename structural_discriminant<typename deref<LeftRef>::type,
typename deref<RightRef>::type>::type>
struct mul_impl;
Works similar to the unary case; the output of the structural_discriminant
is always a cons pair of discriminant values of operands:
... and so on
The additional template parameter Discr should be hidden in the auxiliary class implementing the operation
(such as neg_impl or mul_impl,)
so that the front class (neg or mul) can be used in conjuction with
BuildUnary or BuildBinary. The relation
between the classes is obvious:
template <typename LeftRef, typename RightRef>
struct mul : public mul_impl<LeftRef,RightRef> { };