Skip to content
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
74 changes: 74 additions & 0 deletions include/tensorwrapper/buffer/contiguous.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright 2025 NWChemEx-Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once
#include <tensorwrapper/buffer/replicated.hpp>

namespace tensorwrapper::buffer {

/** @brief Denotes that a buffer is held contiguously.
*
* Contiguous buffers are such that given a pointer to the first element `p`,
* the `i`-th element (`i` is zero based) is given by dereferencing the
* pointer `p + i`. Note that contiguous buffers are always vectors and storing
* higher rank tensors in a contiguous buffer requires "vectorization" of the
* tensor. In C++ vectorization is usually done in row-major format.
*
* @tparam FloatType the type of elements in the buffer.
*/
template<typename FloatType>
class Contiguous : public Replicated {
private:
/// Type *this derives from
using my_base_type = Replicated;

public:
/// Type of each element
using element_type = FloatType;

/// Type of a pointer to a mutable element_type object
using pointer = element_type*;

/// Type of a pointer to a read-only element_type object
using const_pointer = const element_type*;

/// Type used for offsets and indexing
using size_type = std::size_t;

// Pull in base's ctors
using my_base_type::my_base_type;

/// Returns the number of elements in contiguous memory
size_type size() const noexcept { return size_(); }

/// Returns a mutable pointer to the first element in contiguous memory
pointer data() noexcept { return data_(); }

/// Returns a read-only pointer to the first element in contiguous memory
const_pointer data() const noexcept { return data_(); }

protected:
/// Derived class can override if it likes
virtual size_type size_() const noexcept { return layout().shape().size(); }

/// Derived class should implement according to data() description
virtual pointer data_() noexcept = 0;

/// Derived class should implement according to data() const description
virtual const_pointer data_() const noexcept = 0;
};

} // namespace tensorwrapper::buffer
20 changes: 15 additions & 5 deletions include/tensorwrapper/buffer/eigen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

#pragma once
#include <tensorwrapper/backends/eigen.hpp>
#include <tensorwrapper/buffer/replicated.hpp>
#include <tensorwrapper/buffer/contiguous.hpp>

#ifdef ENABLE_SIGMA
#include <sigma/sigma.hpp>
Expand All @@ -31,19 +31,25 @@ namespace tensorwrapper::buffer {
*
*/
template<typename FloatType, unsigned short Rank>
class Eigen : public Replicated {
class Eigen : public Contiguous<FloatType> {
private:
/// Type of *this
using my_type = Eigen<FloatType, Rank>;

/// Type *this derives from
using my_base_type = Replicated;
using my_base_type = Contiguous<FloatType>;

public:
/// Pull in base class's types
using typename my_base_type::buffer_base_pointer;
using typename my_base_type::const_buffer_base_reference;
using typename my_base_type::const_labeled_reference;
using typename my_base_type::const_layout_reference;
using typename my_base_type::const_pointer;
using typename my_base_type::dsl_reference;
using typename my_base_type::label_type;
using typename my_base_type::pointer;
using typename my_base_type::polymorphic_base;

/// Type of a rank @p Rank tensor using floats of type @p FloatType
using data_type = eigen::data_type<FloatType, Rank>;
Expand Down Expand Up @@ -74,7 +80,7 @@ class Eigen : public Replicated {
*/
template<typename DataType>
Eigen(DataType&& t, const_layout_reference layout) :
Replicated(layout), m_tensor_(std::forward<DataType>(t)) {}
my_base_type(layout), m_tensor_(std::forward<DataType>(t)) {}

/** @brief Initializes *this with a copy of @p other.
*
Expand Down Expand Up @@ -185,7 +191,7 @@ class Eigen : public Replicated {

/// Implements are_equal by calling are_equal_impl_
bool are_equal_(const_buffer_base_reference rhs) const noexcept override {
return my_base_type::are_equal_impl_<my_type>(rhs);
return my_base_type::template are_equal_impl_<my_type>(rhs);
}

/// Implements addition_assignment by calling addition_assignment on state
Expand All @@ -210,6 +216,10 @@ class Eigen : public Replicated {
dsl_reference scalar_multiplication_(label_type this_labels, double scalar,
const_labeled_reference rhs) override;

pointer data_() noexcept override { return m_tensor_.data(); }

const_pointer data_() const noexcept override { return m_tensor_.data(); }

/// Implements to_string
typename polymorphic_base::string_type to_string_() const override;

Expand Down
3 changes: 1 addition & 2 deletions src/tensorwrapper/buffer/eigen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,7 @@ typename EIGEN::dsl_reference EIGEN::scalar_multiplication_(
}

TPARAMS
typename detail_::PolymorphicBase<BufferBase>::string_type EIGEN::to_string_()
const {
typename EIGEN::polymorphic_base::string_type EIGEN::to_string_() const {
std::stringstream ss;
ss << m_tensor_;
return ss.str();
Expand Down
66 changes: 66 additions & 0 deletions tests/cxx/unit_tests/tensorwrapper/buffer/contiguous.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2024 NWChemEx-Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "../testing/testing.hpp"
#include <tensorwrapper/buffer/eigen.hpp>
#include <tensorwrapper/layout/physical.hpp>
#include <tensorwrapper/shape/smooth.hpp>

using namespace tensorwrapper;
using namespace buffer;

/* Testing strategy:
*
* - Contiguous is an abstract class. To test it we must create an instance of
* a derived class. We then will upcast to Contiguous and perform checks
* through the BufferBase interface.

*
*/

TEMPLATE_LIST_TEST_CASE("Contiguous", "", testing::floating_point_types) {
using base_type = Contiguous<TestType>;
auto t0 = testing::eigen_scalar<TestType>();
auto t1 = testing::eigen_vector<TestType>();

auto& base0 = static_cast<base_type&>(t0);
auto& base1 = static_cast<base_type&>(t1);

SECTION("size") {
REQUIRE(base0.size() == 1);
REQUIRE(base1.size() == 5);
}

SECTION("data()") {
REQUIRE(*base0.data() == TestType(42.0));

REQUIRE(*(base1.data() + 0) == TestType(0.0));
REQUIRE(*(base1.data() + 1) == TestType(1.0));
REQUIRE(*(base1.data() + 2) == TestType(2.0));
REQUIRE(*(base1.data() + 3) == TestType(3.0));
REQUIRE(*(base1.data() + 4) == TestType(4.0));
}

SECTION("data() const") {
REQUIRE(*std::as_const(base0).data() == TestType(42.0));

REQUIRE(*(std::as_const(base1).data() + 0) == TestType(0.0));
REQUIRE(*(std::as_const(base1).data() + 1) == TestType(1.0));
REQUIRE(*(std::as_const(base1).data() + 2) == TestType(2.0));
REQUIRE(*(std::as_const(base1).data() + 3) == TestType(3.0));
REQUIRE(*(std::as_const(base1).data() + 4) == TestType(4.0));
}
}
8 changes: 1 addition & 7 deletions tests/cxx/unit_tests/tensorwrapper/buffer/eigen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,6 @@
using namespace tensorwrapper;
using namespace testing;

#ifdef ENABLE_SIGMA
using types2test = std::tuple<float, double, sigma::UFloat, sigma::UDouble>;
#else
using types2test = std::tuple<float, double>;
#endif

namespace {

template<typename FloatType, typename LHSType, typename RHSType>
Expand All @@ -47,7 +41,7 @@ void compare_eigen(const LHSType& lhs, const RHSType& rhs) {

} // namespace

TEMPLATE_LIST_TEST_CASE("Eigen", "", types2test) {
TEMPLATE_LIST_TEST_CASE("Eigen", "", testing::floating_point_types) {
using scalar_buffer = buffer::Eigen<TestType, 0>;
using vector_buffer = buffer::Eigen<TestType, 1>;
using matrix_buffer = buffer::Eigen<TestType, 2>;
Expand Down
13 changes: 12 additions & 1 deletion tests/cxx/unit_tests/tensorwrapper/testing/testing.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,15 @@
#include "helpers.hpp"
#include "inputs.hpp"
#include "layouts.hpp"
#include "shapes.hpp"
#include "shapes.hpp"

namespace tensorwrapper::testing {

#ifdef ENABLE_SIGMA
using floating_point_types =
std::tuple<float, double, sigma::UFloat, sigma::UDouble>;
#else
using floating_point_types = std::tuple<float, double>;
#endif

} // namespace tensorwrapper::testing