diff --git a/cpp/src/arrow/CMakeLists.txt b/cpp/src/arrow/CMakeLists.txt index 6e2294371e7a..d2afaad81d09 100644 --- a/cpp/src/arrow/CMakeLists.txt +++ b/cpp/src/arrow/CMakeLists.txt @@ -771,6 +771,7 @@ if(ARROW_COMPUTE) compute/kernels/scalar_validity.cc compute/kernels/vector_array_sort.cc compute/kernels/vector_cumulative_ops.cc + compute/kernels/vector_demean.cc compute/kernels/vector_pairwise.cc compute/kernels/vector_nested.cc compute/kernels/vector_rank.cc diff --git a/cpp/src/arrow/compute/kernels/CMakeLists.txt b/cpp/src/arrow/compute/kernels/CMakeLists.txt index 7c7b9c8b68d4..bcb73a8bcfa0 100644 --- a/cpp/src/arrow/compute/kernels/CMakeLists.txt +++ b/cpp/src/arrow/compute/kernels/CMakeLists.txt @@ -115,6 +115,12 @@ add_arrow_compute_test(vector_selection_test EXTRA_LINK_LIBS arrow_compute_kernels_testing) +add_arrow_compute_test(vector_demean_test + SOURCES + vector_demean_test.cc + EXTRA_LINK_LIBS + arrow_compute_kernels_testing) + add_arrow_benchmark(vector_hash_benchmark PREFIX "arrow-compute") add_arrow_benchmark(vector_sort_benchmark PREFIX "arrow-compute") add_arrow_benchmark(vector_partition_benchmark PREFIX "arrow-compute") diff --git a/cpp/src/arrow/compute/kernels/vector_demean.cc b/cpp/src/arrow/compute/kernels/vector_demean.cc new file mode 100644 index 000000000000..244ea3ed150d --- /dev/null +++ b/cpp/src/arrow/compute/kernels/vector_demean.cc @@ -0,0 +1,81 @@ + +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 necessary Arrow headers +#include +#include "arrow/compute/api_scalar.h" +#include "arrow/compute/function.h" +#include "arrow/compute/registry.h" +#include "arrow/util/logging.h" + +namespace arrow { +namespace compute { +namespace internal { + +namespace { +// Function documentation +const FunctionDoc demean_doc{ + "Perform a demean operation over all the elements of the array", + ("Returns an array where every element has been removed from \n" + "the mean of the array."), + {"array"}}; + +class DemeanMetaFunction : public MetaFunction { + public: + DemeanMetaFunction() : MetaFunction("demean", Arity::Unary(), demean_doc) {} + + Result ExecuteImpl(const std::vector& args, + const FunctionOptions* options, + ExecContext* ctx) const override { + switch (args[0].kind()) { + case Datum::ARRAY: + case Datum::CHUNKED_ARRAY: { + return Demean(*args[0].make_array(), ctx); + } break; + default: + break; + } + return Status::NotImplemented( + "Unsupported types for demean operation: " + "values=", + args[0].ToString()); + } + + private: + template + static Result Demean(const T& input, ExecContext* ctx) { + // TODO: Expose options? + Datum mean_result; + ARROW_ASSIGN_OR_RAISE( + mean_result, arrow::compute::CumulativeMean(input, CumulativeOptions(), ctx)); + Datum demean_result; + ARROW_ASSIGN_OR_RAISE( + demean_result, + arrow::compute::Subtract(input, mean_result, ArithmeticOptions(), ctx)); + + return demean_result; + } +}; +} // namespace + +void RegisterVectorDemean(FunctionRegistry* registry) { + DCHECK_OK(registry->AddFunction(std::make_shared())); +} +} // namespace internal +} // namespace compute +} // namespace arrow diff --git a/cpp/src/arrow/compute/kernels/vector_demean_test.cc b/cpp/src/arrow/compute/kernels/vector_demean_test.cc new file mode 100644 index 000000000000..4d98db490fcc --- /dev/null +++ b/cpp/src/arrow/compute/kernels/vector_demean_test.cc @@ -0,0 +1,52 @@ + +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 "arrow/compute/api.h" +#include "arrow/compute/kernels/test_util.h" +#include "arrow/compute/util.h" +#include "arrow/result.h" +#include "arrow/status.h" +#include "arrow/testing/gtest_util.h" +#include "arrow/testing/matchers.h" + +namespace arrow { +namespace compute { + +TEST(TestDemean, BasicDemean) { + constexpr int data_bufndx{1}; + const std::vector test_result{0, 0, 0, 0, 0, 0}; + const std::vector test_values{1, 1, 1, 1, 1, 1}; + Int32Builder input_builder; + ASSERT_OK(input_builder.Reserve(test_values.size())); + ASSERT_OK(input_builder.AppendValues(test_values)); + ASSERT_OK_AND_ASSIGN(auto test_inputs, input_builder.Finish()); + + ASSERT_OK_AND_ASSIGN(Datum demean_result, CallFunction("demean", {test_inputs})); + auto result_data = *(demean_result.array()); + + // validate each value + for (int val_ndx = 0; val_ndx < test_inputs->length(); ++val_ndx) { + int32_t expected_value = test_result[val_ndx]; + int32_t actual_value = result_data.GetValues(data_bufndx)[val_ndx]; + ASSERT_EQ(expected_value, actual_value); + } +} +} // namespace compute +} // namespace arrow diff --git a/cpp/src/arrow/compute/registry.cc b/cpp/src/arrow/compute/registry.cc index 0f535eb37326..9149903709fc 100644 --- a/cpp/src/arrow/compute/registry.cc +++ b/cpp/src/arrow/compute/registry.cc @@ -313,6 +313,7 @@ static std::unique_ptr CreateBuiltInRegistry() { // Vector functions RegisterVectorArraySort(registry.get()); RegisterVectorCumulativeSum(registry.get()); + RegisterVectorDemean(registry.get()); RegisterVectorNested(registry.get()); RegisterVectorRank(registry.get()); RegisterVectorReplace(registry.get()); diff --git a/cpp/src/arrow/compute/registry_internal.h b/cpp/src/arrow/compute/registry_internal.h index cdc9f804e72f..3b43bb9863ec 100644 --- a/cpp/src/arrow/compute/registry_internal.h +++ b/cpp/src/arrow/compute/registry_internal.h @@ -46,6 +46,7 @@ void RegisterScalarOptions(FunctionRegistry* registry); // Vector functions void RegisterVectorArraySort(FunctionRegistry* registry); void RegisterVectorCumulativeSum(FunctionRegistry* registry); +void RegisterVectorDemean(FunctionRegistry* registry); void RegisterVectorHash(FunctionRegistry* registry); void RegisterVectorNested(FunctionRegistry* registry); void RegisterVectorRank(FunctionRegistry* registry);