// Ceres Solver - A fast non-linear least squares minimizer // Copyright 2022 Google Inc. All rights reserved. // http://ceres-solver.org/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of Google Inc. nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // // Author: jodebo_beck@gmx.de (Johannes Beck) // sergiu.deitsch@gmail.com (Sergiu Deitsch) // // Algorithms to be used together with integer_sequence, like computing the sum // or the exclusive scan (sometimes called exclusive prefix sum) at compile // time. #ifndef CERES_PUBLIC_INTERNAL_INTEGER_SEQUENCE_ALGORITHM_H_ #define CERES_PUBLIC_INTERNAL_INTEGER_SEQUENCE_ALGORITHM_H_ #include #include "ceres/jet_fwd.h" namespace ceres { namespace internal { // Implementation of calculating the sum of an integer sequence. // Recursively instantiate SumImpl and calculate the sum of the N first // numbers. This reduces the number of instantiations and speeds up // compilation. // // Examples: // 1) integer_sequence: // Value = 5 // // 2) integer_sequence: // Value = 4 + 2 + SumImpl>::Value // Value = 4 + 2 + 0 // // 3) integer_sequence: // Value = 2 + 1 + SumImpl>::Value // Value = 2 + 1 + 4 template struct SumImpl; // Strip of and sum the first number. template struct SumImpl> { static constexpr T Value = N + SumImpl>::Value; }; // Strip of and sum the first two numbers. template struct SumImpl> { static constexpr T Value = N1 + N2 + SumImpl>::Value; }; // Strip of and sum the first four numbers. template struct SumImpl> { static constexpr T Value = N1 + N2 + N3 + N4 + SumImpl>::Value; }; // Only one number is left. 'Value' is just that number ('recursion' ends). template struct SumImpl> { static constexpr T Value = N; }; // No number is left. 'Value' is the identity element (for sum this is zero). template struct SumImpl> { static constexpr T Value = T(0); }; // Calculate the sum of an integer sequence. The resulting sum will be stored in // 'Value'. template class Sum { using T = typename Seq::value_type; public: static constexpr T Value = SumImpl::Value; }; // Implementation of calculating an exclusive scan (exclusive prefix sum) of an // integer sequence. Exclusive means that the i-th input element is not included // in the i-th sum. Calculating the exclusive scan for an input array I results // in the following output R: // // R[0] = 0 // R[1] = I[0]; // R[2] = I[0] + I[1]; // R[3] = I[0] + I[1] + I[2]; // ... // // In C++17 std::exclusive_scan does the same operation at runtime (but // cannot be used to calculate the prefix sum at compile time). See // https://en.cppreference.com/w/cpp/algorithm/exclusive_scan for a more // detailed description. // // Example for integer_sequence (seq := integer_sequence): // T , Sum, Ns... , Rs... // ExclusiveScanImpl, seq> // ExclusiveScanImpl, seq> // ExclusiveScanImpl, seq> // ExclusiveScanImpl, seq> // ^^^^^^^^^^^^^^^^^ // resulting sequence template struct ExclusiveScanImpl; template struct ExclusiveScanImpl, std::integer_sequence> { using Type = typename ExclusiveScanImpl, std::integer_sequence>::Type; }; // End of 'recursion'. The resulting type is SeqOut. template struct ExclusiveScanImpl, SeqOut> { using Type = SeqOut; }; // Calculates the exclusive scan of the specified integer sequence. The last // element (the total) is not included in the resulting sequence so they have // same length. This means the exclusive scan of integer_sequence // will be integer_sequence. template class ExclusiveScanT { using T = typename Seq::value_type; public: using Type = typename ExclusiveScanImpl>::Type; }; // Helper to use exclusive scan without typename. template using ExclusiveScan = typename ExclusiveScanT::Type; // Removes all elements from a integer sequence corresponding to specified // ValueToRemove. // // This type should not be used directly but instead RemoveValue. template struct RemoveValueImpl; // Final filtered sequence template struct RemoveValueImpl, std::integer_sequence> { using type = std::integer_sequence; }; // Found a matching value template struct RemoveValueImpl, std::integer_sequence> : RemoveValueImpl, std::integer_sequence> {}; // Move one element from the tail to the head template struct RemoveValueImpl, std::integer_sequence> : RemoveValueImpl, std::integer_sequence> {}; // Start recursion by splitting the integer sequence into two separate ones template struct RemoveValueImpl> : RemoveValueImpl, std::integer_sequence> {}; // RemoveValue takes an integer Sequence of arbitrary type and removes all // elements matching ValueToRemove. // // In contrast to RemoveValueImpl, this implementation deduces the value type // eliminating the need to specify it explicitly. // // As an example, RemoveValue, 4>::type will // not transform the type of the original sequence. However, // RemoveValue, 2>::type will generate a new // sequence of type std::integer_sequence by removing the value 2. template struct RemoveValue : RemoveValueImpl { }; // Convenience template alias for RemoveValue. template using RemoveValue_t = typename RemoveValue::type; // Determines whether the values of an integer sequence are all the same. // // The integer sequence must contain at least one value. The predicate is // undefined for empty sequences. The evaluation result of the predicate for a // sequence containing only one value is defined to be true. template struct AreAllEqual; // The predicate result for a sequence containing one element is defined to be // true. template struct AreAllEqual> : std::true_type {}; // Recursion end. template struct AreAllEqual> : std::integral_constant {}; // Recursion for sequences containing at least two elements. template // clang-format off struct AreAllEqual > : std::integral_constant < bool, AreAllEqual >::value && AreAllEqual >::value > // clang-format on {}; // Convenience variable template for AreAllEqual. template constexpr bool AreAllEqual_v = AreAllEqual::value; // Predicate determining whether an integer sequence is either empty or all // values are equal. template struct IsEmptyOrAreAllEqual; // Empty case. template struct IsEmptyOrAreAllEqual> : std::true_type {}; // General case for sequences containing at least one value. template struct IsEmptyOrAreAllEqual> : AreAllEqual> {}; // Convenience variable template for IsEmptyOrAreAllEqual. template constexpr bool IsEmptyOrAreAllEqual_v = IsEmptyOrAreAllEqual::value; } // namespace internal } // namespace ceres #endif // CERES_PUBLIC_INTERNAL_INTEGER_SEQUENCE_ALGORITHM_H_