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
1 change: 1 addition & 0 deletions include/tensorwrapper/operations/operations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#pragma once
#include <tensorwrapper/operations/approximately_equal.hpp>
#include <tensorwrapper/operations/norm.hpp>
#include <tensorwrapper/operations/power.hpp>

/// Namespace for free functions that act on tensors
namespace tensorwrapper::operations {}
24 changes: 24 additions & 0 deletions include/tensorwrapper/operations/power.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2026 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/tensor/tensor.hpp>

namespace tensorwrapper::operations {

/** @brief Appplies a power element-wise to a tensor */
Tensor power(Tensor A, double pow);
} // namespace tensorwrapper::operations
16 changes: 16 additions & 0 deletions include/tensorwrapper/types/floating_point.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,17 @@ T exp(T value) {
}
}

template<typename T>
T pow(T value, double pow) {
if constexpr(is_uncertain_v<T>) {
return sigma::pow(value, pow);
} else if constexpr(is_interval_v<T>) {
return T(sigma::pow(value, pow));
} else {
return std::pow(value, pow);
}
}

#define TW_APPLY_FLOATING_POINT_TYPES(MACRO_IN) \
MACRO_IN(float); \
MACRO_IN(double); \
Expand Down Expand Up @@ -125,6 +136,11 @@ T exp(T value) {
return std::exp(value);
}

template<typename T>
T pow(T value, double pow) {
return std::pow(value, pow);
}

#define TW_APPLY_FLOATING_POINT_TYPES(MACRO_IN) \
MACRO_IN(float); \
MACRO_IN(double)
Expand Down
24 changes: 24 additions & 0 deletions include/tensorwrapper/utilities/diagonal_matrix.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2026 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/tensor/tensor.hpp>

namespace tensorwrapper::utilities {

Tensor diagonal_matrix(const Tensor& diagonal_elements);

} // namespace tensorwrapper::utilities
37 changes: 37 additions & 0 deletions include/tensorwrapper/utilities/make_tensor.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2026 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/contiguous.hpp>
#include <tensorwrapper/tensor/tensor_class.hpp>
namespace tensorwrapper::utilities {

template<typename BeginIterator, typename EndIterator>
Tensor make_tensor(std::vector<std::size_t> shape, BeginIterator begin,
EndIterator end) {
shape::Smooth smooth_shape(shape.begin(), shape.end());
std::vector data(begin, end);
buffer::Contiguous buffer(data, smooth_shape);
return Tensor(std::move(smooth_shape), std::move(buffer));
}

template<typename ContainerType>
Tensor make_tensor(std::initializer_list<std::size_t> shape,
ContainerType&& value) {
return make_tensor(shape, value.begin(), value.end());
}

} // namespace tensorwrapper::utilities
2 changes: 2 additions & 0 deletions include/tensorwrapper/utilities/utilities.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

#pragma once
#include <tensorwrapper/utilities/block_diagonal_matrix.hpp>
#include <tensorwrapper/utilities/diagonal_matrix.hpp>
#include <tensorwrapper/utilities/make_tensor.hpp>
#include <tensorwrapper/utilities/to_json.hpp>

/// Namespace for helper functions
Expand Down
50 changes: 50 additions & 0 deletions src/tensorwrapper/operations/power.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2026 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/contiguous.hpp>
#include <tensorwrapper/operations/power.hpp>
#include <tensorwrapper/types/floating_point.hpp>

namespace tensorwrapper::operations {
namespace {

class PowerKernel {
public:
PowerKernel(double pow) : m_pow_(pow) {}

template<typename FloatType>
void operator()(std::span<FloatType> A) const {
if constexpr(std::is_const_v<FloatType>) {
// This path is only for the compiler, we won't actually get to
// it.
throw std::runtime_error("Can't modify const data");
} else {
for(auto& a : A) { a = types::pow(a, m_pow_); }
}
}

private:
double m_pow_;
};
} // namespace

Tensor power(Tensor A, double pow) {
PowerKernel kernel(pow);
auto& buffer = make_contiguous(A.buffer());
buffer::visit_contiguous_buffer(kernel, buffer);
return A;
}
} // namespace tensorwrapper::operations
48 changes: 48 additions & 0 deletions src/tensorwrapper/utilities/diagonal_matrix.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright 2026 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 <stdexcept>
#include <tensorwrapper/buffer/contiguous.hpp>
#include <tensorwrapper/utilities/diagonal_matrix.hpp>

namespace tensorwrapper::utilities {
namespace {
struct Kernel {
template<typename FloatType>
auto operator()(const std::span<FloatType>& diagonal_elements) {
using clean_type = std::decay_t<FloatType>;
const auto n = diagonal_elements.size();
shape::Smooth new_shape{n, n};
std::vector<clean_type> data(n * n, 0);
for(std::size_t i = 0; i < n; ++i) {
data[i * n + i] = diagonal_elements[i];
}
buffer::Contiguous buffer(data, new_shape);
return Tensor(std::move(new_shape), std::move(buffer));
}
};
} // namespace

Tensor diagonal_matrix(const Tensor& diagonal_elements) {
if(diagonal_elements.rank() != 1) {
throw std::runtime_error("Diagonal elements must be a vector");
}
Kernel k;
auto& buffer = make_contiguous(diagonal_elements.buffer());
return buffer::visit_contiguous_buffer(k, buffer);
}

} // namespace tensorwrapper::utilities
45 changes: 45 additions & 0 deletions tests/cxx/unit_tests/tensorwrapper/operations/power.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2026 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/operations/approximately_equal.hpp>
#include <tensorwrapper/operations/norm.hpp>
#include <tensorwrapper/utilities/make_tensor.hpp>
#include <testing/testing.hpp>

using namespace tensorwrapper;
using namespace tensorwrapper::operations;
using namespace tensorwrapper::utilities;

TEMPLATE_LIST_TEST_CASE("power", "", types::floating_point_types) {
SECTION("scalar") {
shape::Smooth s{};
Tensor scalar(s, testing::eigen_scalar<TestType>());
auto rv = power(scalar, 2);
REQUIRE(approximately_equal(
rv, Tensor(s, testing::eigen_scalar<TestType>(42 * 42))));
}

SECTION("vector") {
shape::Smooth s{5};
Tensor vector(s, testing::eigen_vector<TestType>());
auto rv = power(vector, 0.5);
TestType sqrt2 = std::sqrt(2);
TestType sqrt3 = std::sqrt(3);
std::vector<TestType> data{0, 1, sqrt2, sqrt3, 2};
auto corr = make_tensor({5}, data.begin(), data.end());
REQUIRE(approximately_equal(rv, corr));
}
}
33 changes: 33 additions & 0 deletions tests/cxx/unit_tests/tensorwrapper/utilities/diagonal_matrix.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2026 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/operations/approximately_equal.hpp>
#include <tensorwrapper/utilities/diagonal_matrix.hpp>
#include <tensorwrapper/utilities/make_tensor.hpp>
#include <testing/testing.hpp>

using namespace tensorwrapper;
using namespace tensorwrapper::operations;
using namespace tensorwrapper::utilities;
using namespace testing;

TEMPLATE_LIST_TEST_CASE("diagonal_matrix", "", types::floating_point_types) {
auto diagonal_values = make_tensor({3}, std::vector<TestType>{1, 2, 3});
auto corr =
make_tensor({3, 3}, std::vector<TestType>{1, 0, 0, 0, 2, 0, 0, 0, 3});
auto result = diagonal_matrix(diagonal_values);
REQUIRE(approximately_equal(result, corr));
}
70 changes: 70 additions & 0 deletions tests/cxx/unit_tests/tensorwrapper/utilities/make_tensor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2026 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/operations/approximately_equal.hpp>
#include <tensorwrapper/utilities/make_tensor.hpp>
#include <testing/testing.hpp>

using namespace tensorwrapper;
using namespace tensorwrapper::operations;
using namespace tensorwrapper::utilities;

TEMPLATE_LIST_TEST_CASE("make_tensor", "", types::floating_point_types) {
SECTION("scalar") {
std::vector<TestType> data{42};
auto tensor = make_tensor({}, data.begin(), data.end());
auto tensor2 = make_tensor({}, data);
Tensor corr(shape::Smooth{}, testing::eigen_scalar<TestType>(42));
REQUIRE(approximately_equal(tensor, corr));
REQUIRE(approximately_equal(tensor2, corr));
}

SECTION("vector") {
std::vector<TestType> data{0, 1, 2, 3, 4};
auto tensor = make_tensor({5}, data.begin(), data.end());
auto tensor2 = make_tensor({5}, data);
Tensor corr(shape::Smooth{5}, testing::eigen_vector<TestType>());
REQUIRE(approximately_equal(tensor, corr));
REQUIRE(approximately_equal(tensor2, corr));
}

SECTION("matrix") {
std::vector<TestType> data{1, 2, 3, 4};
auto tensor = make_tensor({2, 2}, data.begin(), data.end());
auto tensor2 = make_tensor({2, 2}, data);
Tensor corr(shape::Smooth{2, 2}, testing::eigen_matrix<TestType>());
REQUIRE(approximately_equal(tensor, corr));
REQUIRE(approximately_equal(tensor2, corr));
}
SECTION("tensor3") {
std::vector<TestType> data{1, 2, 3, 4, 5, 6, 7, 8};
auto tensor = make_tensor({2, 2, 2}, data.begin(), data.end());
auto tensor2 = make_tensor({2, 2, 2}, data);
Tensor corr(shape::Smooth{2, 2, 2}, testing::eigen_tensor3<TestType>());
REQUIRE(approximately_equal(tensor, corr));
REQUIRE(approximately_equal(tensor2, corr));
}
SECTION("tensor4") {
std::vector<TestType> data{1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16};
auto tensor = make_tensor({2, 2, 2, 2}, data.begin(), data.end());
auto tensor2 = make_tensor({2, 2, 2, 2}, data);
Tensor corr(shape::Smooth{2, 2, 2, 2},
testing::eigen_tensor4<TestType>());
REQUIRE(approximately_equal(tensor, corr));
REQUIRE(approximately_equal(tensor2, corr));
}
}
Loading