Skip to content

Commit

Permalink
Moved edge index implementation to a separate namespace (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
arsenius7 authored May 28, 2019
1 parent 3ebd44e commit e4618d8
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 95 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ endif()

set(SONATA_SRC
src/common.cpp
src/edge_index.cpp
src/edges.cpp
src/hdf5_mutex.cpp
src/nodes.cpp
Expand Down
2 changes: 1 addition & 1 deletion extlib/HighFive
Submodule HighFive updated 37 files
+5 −4 .clang-format
+131 −9 .travis.yml
+10 −2 CMake/PackageConfig.cmake
+7 −3 CMake/config/CompilerFlagsHelpers.cmake
+1 −0 CMake/portability/CheckCXX11Portability.cmake
+35 −7 CMakeLists.txt
+64 −8 README.md
+0 −18 ci/travis/install.sh
+21 −2 include/highfive/H5DataSet.hpp
+25 −9 include/highfive/H5DataSpace.hpp
+222 −0 include/highfive/H5Easy.hpp
+1 −1 include/highfive/H5Exception.hpp
+20 −19 include/highfive/H5File.hpp
+2 −7 include/highfive/H5FileDriver.hpp
+83 −54 include/highfive/H5PropertyList.hpp
+1 −1 include/highfive/bits/H5Annotate_traits_misc.hpp
+53 −60 include/highfive/bits/H5Converter_misc.hpp
+1 −1 include/highfive/bits/H5DataType_misc.hpp
+15 −9 include/highfive/bits/H5Dataspace_misc.hpp
+187 −0 include/highfive/bits/H5Easy_Eigen.hpp
+79 −0 include/highfive/bits/H5Easy_misc.hpp
+174 −0 include/highfive/bits/H5Easy_scalar.hpp
+96 −0 include/highfive/bits/H5Easy_vector.hpp
+138 −0 include/highfive/bits/H5Easy_xtensor.hpp
+3 −8 include/highfive/bits/H5FileDriver_misc.hpp
+6 −6 include/highfive/bits/H5File_misc.hpp
+32 −28 include/highfive/bits/H5Node_traits.hpp
+46 −30 include/highfive/bits/H5Node_traits_misc.hpp
+90 −66 include/highfive/bits/H5PropertyList_misc.hpp
+6 −2 include/highfive/bits/H5Slice_traits_misc.hpp
+4 −4 src/examples/boost_multi_array_2D.cpp
+4 −1 src/examples/boost_ublas_double.cpp
+94 −0 src/examples/easy_load_dump.cpp
+3 −9 tests/unit/CMakeLists.txt
+244 −97 tests/unit/tests_high_five_base.cpp
+222 −0 tests/unit/tests_high_five_easy.cpp
+1 −1 tests/unit/tests_high_five_parallel.cpp
111 changes: 111 additions & 0 deletions src/edge_index.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*************************************************************************
* Copyright (C) 2018-2019 Blue Brain Project
*
* This file is part of 'libsonata', distributed under the terms
* of the GNU Lesser General Public License.
*
* See top-level LICENSE.txt file for details.
*************************************************************************/

#include "edge_index.h"

#include <bbp/sonata/common.h>

#include <cstdint>
#include <set>
#include <vector>


namespace bbp {
namespace sonata {
namespace edge_index {

namespace {

typedef std::vector<std::vector<uint64_t>> RawIndex;

const char* SOURCE_INDEX_GROUP = "indices/source_to_target";
const char* TARGET_INDEX_GROUP = "indices/target_to_source";
const char* NODE_ID_TO_RANGES_DSET = "node_id_to_ranges";
const char* RANGE_TO_EDGE_ID_DSET = "range_to_edge_id";

} // unnamed namespace


const HighFive::Group sourceIndex(const HighFive::Group& h5Root)
{
if (!h5Root.exist(SOURCE_INDEX_GROUP)) {
throw SonataError("No source index group found");
}
return h5Root.getGroup(SOURCE_INDEX_GROUP);
}


const HighFive::Group targetIndex(const HighFive::Group& h5Root)
{
if (!h5Root.exist(TARGET_INDEX_GROUP)) {
throw SonataError("No target index group found");
}
return h5Root.getGroup(TARGET_INDEX_GROUP);
}


Selection resolve(const HighFive::Group& indexGroup, const NodeID nodeID)
{
if (nodeID >= indexGroup.getDataSet(NODE_ID_TO_RANGES_DSET).getSpace().getDimensions()[0]) {
// Returning empty set for out-of-range node IDs, to be aligned with SYN2 reader implementation
// TODO: throw a SonataError instead
return Selection({});
}

RawIndex primaryRange;
indexGroup
.getDataSet(NODE_ID_TO_RANGES_DSET)
.select({ nodeID, 0 }, { 1, 2 })
.read(primaryRange);

const uint64_t primaryRangeBegin = primaryRange[0][0];
const uint64_t primaryRangeEnd = primaryRange[0][1];

if (primaryRangeBegin >= primaryRangeEnd) {
return Selection({});
}

RawIndex secondaryRange;
indexGroup
.getDataSet(RANGE_TO_EDGE_ID_DSET)
.select({ primaryRangeBegin, 0 }, { primaryRangeEnd - primaryRangeBegin, 2 })
.read(secondaryRange);

Selection::Ranges ranges;
ranges.reserve(secondaryRange.size());

for (const auto& row: secondaryRange) {
ranges.emplace_back(row[0], row[1]);
}

return Selection(std::move(ranges));
}


Selection resolve(const HighFive::Group& indexGroup, const std::vector<NodeID>& nodeIDs)
{
if (nodeIDs.size() == 1) {
return resolve(indexGroup, nodeIDs[0]);
}
// TODO optimize: bulk read for primary index
// TODO optimize: range merging
std::set<EdgeID> merged;
for (NodeID nodeID : nodeIDs) {
const auto ids = resolve(indexGroup, nodeID).flatten();
merged.insert(ids.begin(), ids.end());
}
std::vector<EdgeID> result;
result.reserve(merged.size());
std::copy(merged.begin(), merged.end(), std::back_inserter(result));
return Selection::fromValues(result);
}

}
}
} // namespace bbp::sonata::edge_index
29 changes: 29 additions & 0 deletions src/edge_index.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*************************************************************************
* Copyright (C) 2018-2019 Blue Brain Project
*
* This file is part of 'libsonata', distributed under the terms
* of the GNU Lesser General Public License.
*
* See top-level LICENSE.txt file for details.
*************************************************************************/

#pragma once

#include <bbp/sonata/population.h>

#include <highfive/H5File.hpp>
#include <highfive/H5Group.hpp>

namespace bbp {
namespace sonata {
namespace edge_index {

const HighFive::Group sourceIndex(const HighFive::Group& h5Root);
const HighFive::Group targetIndex(const HighFive::Group& h5Root);

Selection resolve(const HighFive::Group& indexGroup, NodeID nodeID);
Selection resolve(const HighFive::Group& indexGroup, const std::vector<NodeID>& nodeIDs);

}
}
} // namespace bbp::sonata::edge_index
89 changes: 22 additions & 67 deletions src/edges.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "population.hpp"
#include "hdf5_mutex.hpp"
#include "edge_index.h"

#include <bbp/sonata/common.h>
#include <bbp/sonata/edges.h>
Expand All @@ -19,6 +20,15 @@
#include <algorithm>


namespace {

const char* SOURCE_NODE_ID_DSET = "source_node_id";
const char* TARGET_NODE_ID_DSET = "target_node_id";
const char* NODE_POPULATION_ATTR = "node_population";

} // unnamed namespace


namespace bbp {
namespace sonata {

Expand All @@ -36,7 +46,7 @@ std::string EdgePopulation::source() const
{
HDF5_LOCK_GUARD
std::string result;
impl_->h5Root.getDataSet("source_node_id").getAttribute("node_population").read(result);
impl_->h5Root.getDataSet(SOURCE_NODE_ID_DSET).getAttribute(NODE_POPULATION_ATTR).read(result);
return result;
}

Expand All @@ -45,100 +55,45 @@ std::string EdgePopulation::target() const
{
HDF5_LOCK_GUARD
std::string result;
impl_->h5Root.getDataSet("target_node_id").getAttribute("node_population").read(result);
impl_->h5Root.getDataSet(TARGET_NODE_ID_DSET).getAttribute(NODE_POPULATION_ATTR).read(result);
return result;
}


std::vector<NodeID> EdgePopulation::sourceNodeIDs(const Selection& selection) const
{
HDF5_LOCK_GUARD
const auto dset = impl_->h5Root.getDataSet("source_node_id");
const auto dset = impl_->h5Root.getDataSet(SOURCE_NODE_ID_DSET);
return _readSelection<NodeID>(dset, selection);
}


std::vector<NodeID> EdgePopulation::targetNodeIDs(const Selection& selection) const
{
HDF5_LOCK_GUARD
const auto dset = impl_->h5Root.getDataSet("target_node_id");
const auto dset = impl_->h5Root.getDataSet(TARGET_NODE_ID_DSET);
return _readSelection<NodeID>(dset, selection);
}


namespace {

Selection _resolveIndex(const HighFive::Group& indexGroup, const NodeID nodeID)
{
typedef std::vector<std::vector<uint64_t>> RawIndex;

if (nodeID >= indexGroup.getDataSet("node_id_to_ranges").getSpace().getDimensions()[0]) {
// Returning empty set for out-of-range node IDs, to be aligned with SYN2 reader implementation
// TODO: throw a SonataError instead
return Selection({});
}

RawIndex primaryRange;
indexGroup
.getDataSet("node_id_to_ranges")
.select({ nodeID, 0 }, { 1, 2 })
.read(primaryRange);

const uint64_t primaryRangeBegin = primaryRange[0][0];
const uint64_t primaryRangeEnd = primaryRange[0][1];

if (primaryRangeBegin >= primaryRangeEnd) {
return Selection({});
}

RawIndex secondaryRange;
indexGroup
.getDataSet("range_to_edge_id")
.select({ primaryRangeBegin, 0 }, { primaryRangeEnd - primaryRangeBegin, 2 })
.read(secondaryRange);

Selection::Ranges ranges;
ranges.reserve(secondaryRange.size());

for (const auto& row: secondaryRange) {
ranges.emplace_back(row[0], row[1]);
}

return Selection(std::move(ranges));
}


Selection _resolveIndex(const HighFive::Group& indexGroup, const std::vector<NodeID>& nodeIDs)
{
if (nodeIDs.size() == 1) {
return _resolveIndex(indexGroup, nodeIDs[0]);
}
// TODO optimize: bulk read for primary index
// TODO optimize: range merging
std::set<EdgeID> result;
for (NodeID nodeID : nodeIDs) {
const auto ids = _resolveIndex(indexGroup, nodeID).flatten();
result.insert(ids.begin(), ids.end());
}
return _selectionFromValues(result.begin(), result.end());
}

} // unnamed namespace


Selection EdgePopulation::afferentEdges(const std::vector<NodeID>& target) const
{
HDF5_LOCK_GUARD
const auto& indexGroup = impl_->h5Root.getGroup("indices/target_to_source");
return _resolveIndex(indexGroup, target);
return edge_index::resolve(
edge_index::targetIndex(impl_->h5Root),
target
);
}


Selection EdgePopulation::efferentEdges(const std::vector<NodeID>& source) const
{
HDF5_LOCK_GUARD
const auto& indexGroup = impl_->h5Root.getGroup("indices/source_to_target");
return _resolveIndex(indexGroup, source);
return edge_index::resolve(
edge_index::sourceIndex(impl_->h5Root),
source
);
}


Expand Down
21 changes: 20 additions & 1 deletion src/population.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,26 @@ Selection::Selection(const Selection::Ranges& ranges)

Selection Selection::fromValues(const Selection::Values& values)
{
return _selectionFromValues(values.begin(), values.end());
Selection::Ranges ranges;

Selection::Range range{ 0, 0 };
for (const auto v: values) {
if (v == range.second) {
++range.second;
} else {
if (range.first < range.second) {
ranges.push_back(range);
}
range.first = v;
range.second = v + 1;
}
}

if (range.first < range.second) {
ranges.push_back(range);
}

return Selection(std::move(ranges));
}


Expand Down
26 changes: 0 additions & 26 deletions src/population.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,32 +39,6 @@ std::set<std::string> _listChildren(const HighFive::Group& group, const std::set
}


template<typename Iterator>
Selection _selectionFromValues(Iterator first, Iterator last)
{
Selection::Ranges ranges;

Selection::Range range{ 0, 0 };
for (Iterator it = first; it != last; ++it) {
if (*it == range.second) {
++range.second;
} else {
if (range.first < range.second) {
ranges.push_back(range);
}
range.first = *it;
range.second = *it + 1;
}
}

if (range.first < range.second) {
ranges.push_back(range);
}

return Selection(std::move(ranges));
}


template<typename T>
std::vector<T> _readChunk(const HighFive::DataSet& dset, const Selection::Range& range)
{
Expand Down

0 comments on commit e4618d8

Please sign in to comment.