diff --git a/include/tensorwrapper/operations/norm.hpp b/include/tensorwrapper/operations/norm.hpp new file mode 100644 index 00000000..d0917fa5 --- /dev/null +++ b/include/tensorwrapper/operations/norm.hpp @@ -0,0 +1,33 @@ +/* + * 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 + +namespace tensorwrapper::operations { + +/** @brief Returns the infinity norm of @p t. + * + * The infinity norm of the tensor @p t is the element of @p t with the + * largest absolute value. + * + * @param[in] t The tensor to take the norm of. + * + * @return The infinity norm of @p t. + */ +Tensor infinity_norm(const Tensor& t); + +} // namespace tensorwrapper::operations \ No newline at end of file diff --git a/include/tensorwrapper/operations/operations.hpp b/include/tensorwrapper/operations/operations.hpp index 8cba2b83..afd96c57 100644 --- a/include/tensorwrapper/operations/operations.hpp +++ b/include/tensorwrapper/operations/operations.hpp @@ -16,6 +16,7 @@ #pragma once #include +#include /// Namespace for free functions that act on tensors namespace tensorwrapper::operations {} \ No newline at end of file diff --git a/include/tensorwrapper/types/floating_point.hpp b/include/tensorwrapper/types/floating_point.hpp index 0d273333..e3ef7f9c 100644 --- a/include/tensorwrapper/types/floating_point.hpp +++ b/include/tensorwrapper/types/floating_point.hpp @@ -28,6 +28,19 @@ using udouble = sigma::UDouble; using floating_point_types = std::tuple; +template +constexpr bool is_uncertain_v = + std::is_same_v || std::is_same_v; + +template +T fabs(T value) { + if constexpr(is_uncertain_v) { + return sigma::fabs(value); + } else { + return std::fabs(value); + } +} + #define TW_APPLY_FLOATING_POINT_TYPES(MACRO_IN) \ MACRO_IN(float); \ MACRO_IN(double); \ @@ -40,6 +53,14 @@ using udouble = double; using floating_point_types = std::tuple; +template +constexpr bool is_uncertain_v = false; + +template +T fabs(T value) { + return std::fabs(value); +} + #define TW_APPLY_FLOATING_POINT_TYPES(MACRO_IN) \ MACRO_IN(float); \ MACRO_IN(double) diff --git a/src/tensorwrapper/operations/norm.cpp b/src/tensorwrapper/operations/norm.cpp new file mode 100644 index 00000000..3021960d --- /dev/null +++ b/src/tensorwrapper/operations/norm.cpp @@ -0,0 +1,49 @@ +/* + * 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 +#include +#include +#include + +namespace tensorwrapper::operations { +namespace { +struct InfinityKernel { + template + Tensor run(const buffer::BufferBase& t) { + using allocator_type = allocator::Eigen; + allocator_type alloc(t.allocator().runtime()); + FloatType max_element{0.0}; + const auto& buffer_down = alloc.rebind(t); + for(std::size_t i = 0; i < buffer_down.size(); ++i) { + auto elem = types::fabs(*(buffer_down.data() + i)); + if(elem > max_element) max_element = elem; + } + shape::Smooth s{}; + layout::Physical l(s); + auto pbuffer = alloc.construct(l, max_element); + return Tensor(s, std::move(pbuffer)); + } +}; + +} // namespace + +Tensor infinity_norm(const Tensor& t) { + InfinityKernel k; + return utilities::floating_point_dispatch(k, t.buffer()); +} + +} // namespace tensorwrapper::operations \ No newline at end of file diff --git a/tests/cxx/unit_tests/tensorwrapper/operations/norm.cpp b/tests/cxx/unit_tests/tensorwrapper/operations/norm.cpp new file mode 100644 index 00000000..e6ce3540 --- /dev/null +++ b/tests/cxx/unit_tests/tensorwrapper/operations/norm.cpp @@ -0,0 +1,63 @@ +/* + * 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 +#include +#include + +using namespace tensorwrapper; +using namespace tensorwrapper::operations; + +TEMPLATE_LIST_TEST_CASE("infinity_norm", "", types::floating_point_types) { + SECTION("scalar") { + shape::Smooth s{}; + Tensor scalar(s, testing::eigen_scalar()); + auto norm = infinity_norm(scalar); + REQUIRE(approximately_equal(scalar, norm)); + } + + SECTION("vector") { + shape::Smooth s{5}; + Tensor vector(s, testing::eigen_vector()); + Tensor corr(shape::Smooth{}, testing::eigen_scalar(4)); + auto norm = infinity_norm(vector); + REQUIRE(approximately_equal(corr, norm)); + } + + SECTION("matrix") { + shape::Smooth s{2, 2}; + Tensor matrix(s, testing::eigen_matrix()); + Tensor corr(shape::Smooth{}, testing::eigen_scalar(4)); + auto norm = infinity_norm(matrix); + REQUIRE(approximately_equal(corr, norm)); + } + + SECTION("rank 3 tensor") { + shape::Smooth s{2, 2, 2}; + Tensor t(s, testing::eigen_tensor3()); + Tensor corr(shape::Smooth{}, testing::eigen_scalar(8)); + auto norm = infinity_norm(t); + REQUIRE(approximately_equal(corr, norm)); + } + + SECTION("rank 4 tensor") { + shape::Smooth s{2, 2, 2, 2}; + Tensor t(s, testing::eigen_tensor4()); + Tensor corr(shape::Smooth{}, testing::eigen_scalar(16)); + auto norm = infinity_norm(t); + REQUIRE(approximately_equal(corr, norm)); + } +} \ No newline at end of file diff --git a/tests/cxx/unit_tests/tensorwrapper/testing/eigen_buffers.hpp b/tests/cxx/unit_tests/tensorwrapper/testing/eigen_buffers.hpp index e3ab472d..fa62af1e 100644 --- a/tests/cxx/unit_tests/tensorwrapper/testing/eigen_buffers.hpp +++ b/tests/cxx/unit_tests/tensorwrapper/testing/eigen_buffers.hpp @@ -33,9 +33,9 @@ auto make_allocator() { } template -auto eigen_scalar() { +auto eigen_scalar(FloatType value = 42.0) { auto alloc = make_allocator(); - return alloc.construct(42.0); + return alloc.construct(value); } template