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
36 changes: 36 additions & 0 deletions include/tensorwrapper/buffer/eigen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,10 +258,46 @@ class Eigen : public Contiguous<FloatType> {
pimpl_pointer m_pimpl_;
};

/** @brief Wraps downcasting a buffer to an Eigen buffer.
*
* @tparam FloatType The type of the elements in the resulting Buffer.
*
* This function is a convience function for using an allocator to convert
* @p b to a buffer::Eigen object.
*
* @param[in] b The BufferBase object to convert.
*
* @return A reference to @p b after downcasting it.
*/
template<typename FloatType>
Eigen<FloatType>& to_eigen_buffer(BufferBase& b);

/** @brief Wraps downcasting a buffer to an Eigen buffer.
*
* @tparam FloatType The type of the elements in the resulting Buffer.
*
* This function is the same as the non-const overload except that result will
* be read-only.
*
* @param[in] b The BufferBase object to convert.
*
* @return A reference to @p b after downcasting it.
*/
template<typename FloatType>
const Eigen<FloatType>& to_eigen_buffer(const BufferBase& b);

#define DECLARE_EIGEN_BUFFER(TYPE) extern template class Eigen<TYPE>
#define DECLARE_TO_EIGEN_BUFFER(TYPE) \
extern template Eigen<TYPE>& to_eigen_buffer(BufferBase&)
#define DECLARE_TO_CONST_EIGEN_BUFFER(TYPE) \
extern template const Eigen<TYPE>& to_eigen_buffer(const BufferBase&)

TW_APPLY_FLOATING_POINT_TYPES(DECLARE_EIGEN_BUFFER);
TW_APPLY_FLOATING_POINT_TYPES(DECLARE_TO_EIGEN_BUFFER);
TW_APPLY_FLOATING_POINT_TYPES(DECLARE_TO_CONST_EIGEN_BUFFER);

#undef DECLARE_EIGEN_BUFFER
#undef DECLARE_TO_EIGEN_BUFFER
#undef DECLARE_TO_CONST_EIGEN_BUFFER

} // namespace tensorwrapper::buffer
43 changes: 43 additions & 0 deletions include/tensorwrapper/utilities/to_json.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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 <ostream>
#include <tensorwrapper/tensor/tensor.hpp>
namespace tensorwrapper::utilities {

/** @brief Adds a JSON representation of @p to @p os.
*
* This function can be used to print a tensor out in a JSON format. For dense
* tensors this will be as a list of lists such that number of nestings is
* equal to the rank of the tensor.
*
* @param[in,out] os The stream to print @p t to. After the function is called
* @p os will contain the JSON representation of @p t.
* @param[in] t The tensor to print to @p os.
*
* @note Since the caller controls the stream that is passed in, it is assumed
* that the caller has set the stream up to print floating point values
* in their desired format. For example, do
* `os << std::fixed << std::setprecision(8);` prior to calling `to_json`
* to guarantee all floating point values are printed with 8 decimal
* places.
*
* @return This function returns @p os by reference to support chaining.
*/
std::ostream& to_json(std::ostream& os, const Tensor& t);

} // namespace tensorwrapper::utilities
1 change: 1 addition & 0 deletions include/tensorwrapper/utilities/utilities.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#pragma once
#include <tensorwrapper/utilities/floating_point_dispatch.hpp>
#include <tensorwrapper/utilities/to_json.hpp>

/// Namespace for helper functions
namespace tensorwrapper::utilities {}
20 changes: 20 additions & 0 deletions src/tensorwrapper/buffer/eigen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,13 +227,33 @@ typename EIGEN::const_pimpl_reference EIGEN::pimpl_() const {
return *m_pimpl_;
}

TPARAMS
EIGEN& to_eigen_buffer(BufferBase& b) {
using allocator_type = allocator::Eigen<FloatType>;
return allocator_type::rebind(b);
}

TPARAMS
const EIGEN& to_eigen_buffer(const BufferBase& b) {
using allocator_type = allocator::Eigen<FloatType>;
return allocator_type::rebind(b);
}

#undef EIGEN
#undef TPARAMS

#define DEFINE_EIGEN_BUFFER(TYPE) template class Eigen<TYPE>
#define DEFINE_TO_EIGEN_BUFFER(TYPE) \
template Eigen<TYPE>& to_eigen_buffer(BufferBase&)
#define DEFINE_TO_CONST_EIGEN_BUFFER(TYPE) \
template const Eigen<TYPE>& to_eigen_buffer(const BufferBase&)

TW_APPLY_FLOATING_POINT_TYPES(DEFINE_EIGEN_BUFFER);
TW_APPLY_FLOATING_POINT_TYPES(DEFINE_TO_EIGEN_BUFFER);
TW_APPLY_FLOATING_POINT_TYPES(DEFINE_TO_CONST_EIGEN_BUFFER);

#undef DEFINE_EIGEN_BUFFER
#undef DEFINE_TO_EIGEN_BUFFER
#undef DEFINE_TO_CONST_EIGEN_BUFFER

} // namespace tensorwrapper::buffer
56 changes: 56 additions & 0 deletions src/tensorwrapper/utilities/to_json.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* 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.
*/

#include <tensorwrapper/buffer/eigen.hpp>
#include <tensorwrapper/utilities/to_json.hpp>

namespace tensorwrapper::utilities {

using offset_type = std::size_t;
using offset_vector = std::vector<offset_type>;

template<typename DataType>
using buffer_type = buffer::Contiguous<DataType>;

template<typename DataType>
void to_json_(std::ostream& os, const buffer_type<DataType>& t,
offset_vector index) {
const auto& shape = t.layout().shape().as_smooth();
auto rank = index.size();
if(rank == t.rank()) {
os << t.get_elem(index);
return;
} else {
auto n_elements = shape.extent(rank);
index.push_back(0);
os << '[';
for(decltype(n_elements) i = 0; i < n_elements; ++i) {
index[rank] = i;
to_json_(os, t, index);
if(i + 1 < n_elements) os << ',';
}
os << ']';
}
}

std::ostream& to_json(std::ostream& os, const Tensor& t) {
offset_vector i;
const auto& buffer = buffer::to_eigen_buffer<double>(t.buffer());
to_json_(os, buffer, i);
return os;
}

} // namespace tensorwrapper::utilities
14 changes: 14 additions & 0 deletions tests/cxx/unit_tests/tensorwrapper/buffer/eigen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,3 +239,17 @@ TEMPLATE_LIST_TEST_CASE("Eigen", "", types::floating_point_types) {
}
}
}

TEMPLATE_LIST_TEST_CASE("to_eigen_buffer", "", types::floating_point_types) {
using buffer_type = buffer::Eigen<TestType>;

auto pscalar = testing::eigen_scalar<TestType>();
auto& eigen_scalar = static_cast<buffer_type&>(*pscalar);
eigen_scalar.set_elem({}, 10.0);

buffer::BufferBase& scalar_base = eigen_scalar;
REQUIRE(&buffer::to_eigen_buffer<TestType>(scalar_base) == &eigen_scalar);

const buffer::BufferBase& cscalar_base = eigen_scalar;
REQUIRE(&buffer::to_eigen_buffer<TestType>(cscalar_base) == &eigen_scalar);
}
57 changes: 57 additions & 0 deletions tests/cxx/unit_tests/tensorwrapper/utilities/to_json.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* 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 <iomanip>
#include <tensorwrapper/utilities/to_json.hpp>

using namespace tensorwrapper;
using namespace testing;

using tensorwrapper::utilities::to_json;

TEMPLATE_LIST_TEST_CASE("to_json", "", std::tuple<double>) {
Tensor scalar(smooth_scalar_<TestType>());
Tensor vector(smooth_vector_<TestType>());
Tensor matrix(smooth_matrix_<TestType>());
Tensor tensor(smooth_tensor3_<TestType>());

std::stringstream ss;

SECTION("scalar") {
auto pss = &(to_json(ss, scalar));
REQUIRE(pss == &ss);
REQUIRE(ss.str() == "42");
}

SECTION("vector") {
auto pss = &(to_json(ss, vector));
REQUIRE(pss == &ss);
REQUIRE(ss.str() == "[0,1,2,3,4]");
}

SECTION("matrix") {
auto pss = &(to_json(ss, matrix));
REQUIRE(pss == &ss);
REQUIRE(ss.str() == "[[1,2],[3,4]]");
}

SECTION("tensor") {
auto pss = &(to_json(ss, tensor));
REQUIRE(pss == &ss);
REQUIRE(ss.str() == "[[[1,2],[3,4]],[[5,6],[7,8]]]");
}
}