Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moved edge index implementation to a separate namespace #27

Merged
merged 1 commit into from
May 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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