Skip to content

Commit

Permalink
Added first test for operator infrastructure
Browse files Browse the repository at this point in the history
Update #127
  • Loading branch information
eugenwintersberger committed Nov 13, 2017
1 parent 7b9cb27 commit b204ad6
Show file tree
Hide file tree
Showing 6 changed files with 291 additions and 50 deletions.
245 changes: 197 additions & 48 deletions doc/source/users_guide/dataspace_selections.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,53 +33,9 @@ the assembly of rather complex selections from simple ones. It is important to
note here that it is currently not possible to mix :cpp:class:`Points` and
:cpp:class:`Hyperslab` selections. One reason for this is that each of the
two classes uses a different set of operators for combination.


Applying a selection
--------------------

In order to apply a selection you can use the :cpp:class:`SelectionManager`
interface provided by a :cpp:class:`Dataspace` via the public member
:cpp:member:`Dataspace::selection`.

.. figure:: ../images/hdf5_selection_manager.svg
:align: center
:width: 75%

A selection can be applied like this

.. code-block:: cpp
dataspace::Dataspace file_space = dataset.dataspace();
dataspace::Hyperslab slab(...);
file_space.selection(dataspace::SelectionOperation::SET,slab);
.. important::

Both, :cpp:class:`Dataspace` and :cpp:class:`SelectionManager` have a
:cpp:func:`size` method. However, their return value is rather different.
If no selection is applied then both methods return the same value.
However, if a selection is applied :cpp:func:`Dataspace::size` still returns
the total number of elements described by the dataspace while
:cpp:func:`SelectionManager::size` returns the number of selected elements.

.. code-block:: cpp
dataspace::Simple space({1024});
std::cout<<space.size()<<std::endl; // would print 1024
std::cout<<space.selection.size()<<std::endl; // would print 1024
space.selection.none();
std::cout<<space.size()<<std::endl; // would print 1024
std::cout<<space.selection.size()<<std::endl; // would print 0
Multiple selections can be applied onto a single dataspace. The way how
the different selections are combined with each other to form the set of
selected elements can be controlled by *selection operations* which
are determined by the :cpp:enum:`SelectionOperation` enumerations.

Hyperslab selections
--------------------
====================

Hyperslabs allow fairly complex multidimensional selections in a dataspace
which are characterized by 4 quantities
Expand Down Expand Up @@ -155,9 +111,202 @@ The constructor call for such a selection would look like this
Dimensions stride{2,3};
Dimensions count{3,3};
dataspace::Hyperslab{offset,count,stride};
Point selections
----------------
================

.. todo:: write this section


Selection operations and containers
===================================

Point as well as hyperslab selections can be combined by means of different
logical operations. All available operations for selections are represented
by the :cpp:enum:`SelectionOperation` enumeration class.
There are two independent sets of operations available for hyperslab and point
selections.

For point selections there are two simple operations

+-----------+-----------------------------------------------+--------------------+-+
| operation | enumeration | description | |
+===========+===============================================+====================+=+
| append | :cpp:enumerator:`SelectionOperation::APPEND` | add a point to | |
| | | to the end of the | |
| | | list of points | |
+-----------+-----------------------------------------------+--------------------+-+
| prepend | :cpp:enumerator:`SelectionOperation::PREPEND` | add a point to the | |
| | | beginning of the | |
| | | list of points | |
+-----------+-----------------------------------------------+--------------------+-+

It is crucial to understand that selection operators combine a new
selection whith what is already selected in the dataspace.
For hyperslab selections we have

+-----------+--------------------------------------------+-----------------------+-+
| operation | enumeration | description | |
+===========+============================================+=======================+=+
| *set* | :cpp:enumerator:`SelectionOperation::SET` | replace all previous | |
| | | selections with the | |
| | | current one. | |
+-----------+--------------------------------------------+-----------------------+-+
| *or* | :cpp:enumerator:`SelectionOperation::OR` | select elements | |
| | | which are in the | |
| | | current or the | |
| | | previous selection. | |
+-----------+--------------------------------------------+-----------------------+-+
| *and* | :cpp:enumerator:`SelectionOperation::AND` | select elements whcih | |
| | | are in the current | |
| | | and the previous | |
| | | selection. | |
+-----------+--------------------------------------------+-----------------------+-+
| *xor* | :cpp:enumerator:`SelectionOperation::XOR` | select elements which | |
| | | are either in the | |
| | | current or the | |
| | | the previous | |
| | | selection but on in | |
| | | both. | |
+-----------+--------------------------------------------+-----------------------+-+
| *notB* | :cpp:enumerator:`SelectionOperation::NOTB` | select elements whcih | |
| | | are in the current | |
| | | but not in the | |
| | | previous selection. | |
+-----------+--------------------------------------------+-----------------------+-+
| *notA* | :cpp:enumerator:`SelectionOperation::NOTA` | select elements which | |
| | | are in the previous | |
| | | but not in the | |
| | | current one. | |
+-----------+--------------------------------------------+-----------------------+-+

.. todo::

Add here some images showing how these operators work.

Selections can be stored along with their operations in a list for later usage.
For this purpose *h5cpp* defines three utility types

* :cpp:type:`Selection::SharedPointer` which is a smart-pointer to a
selection
* :cpp:type:`SelectionPair` whose first element is a
:cpp:enum:`SelectionOperation` enumeration and its second is
:cpp:type:`Selection::SharedPointer` refering to the selection of
interest
* :cpp:class:`SelectionList` which is an STL list of
:cpp:type:`SelectionPair` instances.

.. note::

As selections use virtual functions to apply themselves to a given
dataspace we cannot simply store a value of :cpp:class:`Selection`.
We thus need a pointer to reference the particular selection.

However, since we are using a smart pointer we never run into
troubles with resouce leaks.

Consider this example

.. code-block:: cpp
dataspace::SelectionList selections;
selections.push_back({dataspace::SelectionOperation::SET,
Selection::SharedPointer(new dataspace::Hyperslab({0,0},{100,100}))});
selections.push_back({dataspace::SelectionOperation::OR,
Selection::SharedPointer(new dataspace::Hyperslab({200,129},{100,100}))});
dataspace::Simple space = ...;
for(auto selection: selections)
selection.second->apply(space,selection.first);
Applying a selection
====================

There are two interfaces which can be used to add a selection to an existing
dataspace:

* the :cpp:class:`SelectionManager` interface provided by the public
:cpp:member:`selection` member of every :cpp:class:`Dataspace` instance
* by means of arithmetic operators.

Furthermore, we have to distinguish between

* *modifying* selection application where an existing dataspace is
modified
* and *copying* application where a new dataspace with the selections
applied is created from an original one.


Using the :cpp:class:`SelectionManager` interface
-------------------------------------------------

In order to apply a selection you can use the :cpp:class:`SelectionManager`
interface provided by a :cpp:class:`Dataspace` via the public member
:cpp:member:`Dataspace::selection`.

.. figure:: ../images/hdf5_selection_manager.svg
:align: center
:width: 75%

A selection can be applied like this

.. code-block:: cpp
dataspace::Dataspace file_space = dataset.dataspace();
dataspace::Hyperslab slab(...);
file_space.selection(dataspace::SelectionOperation::SET,slab);
.. important::

Both, :cpp:class:`Dataspace` and :cpp:class:`SelectionManager` have a
:cpp:func:`size` method. However, their return value is rather different.
If no selection is applied then both methods return the same value.
However, if a selection is applied :cpp:func:`Dataspace::size` still returns
the total number of elements described by the dataspace while
:cpp:func:`SelectionManager::size` returns the number of selected elements.

.. code-block:: cpp
dataspace::Simple space({1024});
std::cout<<space.size()<<std::endl; // would print 1024
std::cout<<space.selection.size()<<std::endl; // would print 1024
space.selection.none();
std::cout<<space.size()<<std::endl; // would print 1024
std::cout<<space.selection.size()<<std::endl; // would print 0
Multiple selections can be applied onto a single dataspace. The way how
the different selections are combined with each other to form the set of
selected elements can be controlled by *selection operations* which
are determined by the :cpp:enum:`SelectionOperation` enumerations.

Operators
---------

Selections can be applied directly to a dataspace using operators. In this
case we have to distinguish two cases

* *modifying* operations where an existing dataspace is modified
* and *constructing* operations which create a new dataspace.


Copying usage of operators

.. code-block:: cpp
Dataspace::Simple orig_space = ...;
function(orig_space | Hyperslab{{0,0},{100,23}}
| Hyperslab{{200,300},{300,342}});
.. todo:: write this section
19 changes: 19 additions & 0 deletions src/dataspace/selection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,25 @@ void Hyperslab::apply(const Dataspace &space,SelectionOperation ops) const
}
}

Dataspace operator||(const Dataspace &space,const Hyperslab &selection)
{
Dataspace new_space(space);

new_space.selection(SelectionOperation::SET,selection);
std::cout<<new_space.selection.size()<<std::endl;
return new_space;
}

Dataspace operator||(const Dataspace &space,const SelectionList &selections)
{
Dataspace new_space(space);

for(auto selection: selections)
new_space.selection(selection.first,*selection.second);

return new_space;
}

SelectionList operator|(const Hyperslab &a,const Hyperslab &b)
{
return {{SelectionOperation::SET,Selection::SharedPointer(new Hyperslab(a))},
Expand Down
5 changes: 3 additions & 2 deletions src/include/h5cpp/dataspace/selection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,9 @@ class DLL_EXPORT Hyperslab : public Selection

};

SelectionList operator|(const Hyperslab &a,const Hyperslab &b);
SelectionList& operator|(SelectionList &selections,const Hyperslab &b);
Dataspace operator||(const Dataspace &space,const Hyperslab &selection);
Dataspace operator||(const Dataspace &space,const SelectionList &selections);



class DLL_EXPORT Points : public Selection
Expand Down
1 change: 1 addition & 0 deletions test/dataspace/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ set(Common_SRC
${dir}/simple_test.cpp
${dir}/hyperslab_simple_test.cpp
${dir}/type_trait_test.cpp
${dir}/selection_operator_set.cpp
PARENT_SCOPE)
11 changes: 11 additions & 0 deletions test/dataspace/hyperslab_simple_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,15 @@ TEST(HyperslabSimple,test_scatter_construction)
EXPECT_EQ(space.selection.size(),30ul);
}

TEST(HyperslabSimple,test_dataspace_copy_with_selection)
{
dataspace::Simple space{{20,1024}};
dataspace::Hyperslab selection{{1,1},{3,10},{2,4}};
space.selection(dataspace::SelectionOperation::SET,selection);
EXPECT_EQ(space.selection.size(),30ul);

dataspace::Simple new_space(space);
EXPECT_EQ(new_space.selection.size(),30ul);
}


60 changes: 60 additions & 0 deletions test/dataspace/selection_operator_set.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// (c) Copyright 2017 DESY,ESS
//
// This file is part of h5pp.
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor
// Boston, MA 02110-1301 USA
// ===========================================================================
//
// Author: Eugen Wintersberger <[email protected]>
// Created on: Nov 13, 2017
//
#include <gtest/gtest.h>

#include <h5cpp/hdf5.hpp>

using namespace hdf5::dataspace;

class SelectionOpsSetTest : public testing::Test
{
public:
Simple space;

SelectionOpsSetTest()
{
space = Simple{{1024,512}};
}

};

TEST_F(SelectionOpsSetTest,simple_set)
{
Simple new_space = space||Hyperslab{{0,0},{100,200}};
EXPECT_EQ(new_space.size(),space.size());
EXPECT_EQ(new_space.selection.size(),100ul*200ul);
}

TEST_F(SelectionOpsSetTest,set_from_list)
{
SelectionList selections{
{SelectionOperation::SET,Selection::SharedPointer(new Hyperslab{{0,0},{100,200}})},
{SelectionOperation::OR,Selection::SharedPointer(new Hyperslab{{101,201},{100,200}})}
};

Simple new_space = space || selections;
EXPECT_EQ(new_space.size(),space.size());
EXPECT_EQ(new_space.selection.size(),2ul*100ul*200ul);
}

0 comments on commit b204ad6

Please sign in to comment.