FuncSketch
Loading...
Searching...
No Matches
general_math_function.h
Go to the documentation of this file.
1/*
2 * Copyright 2026 MusicScience37 (Kenta Kabashima)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
20#pragma once
21
22#include <concepts>
23#include <string>
24#include <string_view>
25#include <tuple>
26#include <utility>
27#include <variant>
28#include <vector>
29
30#include <fmt/base.h>
31#include <fmt/format.h>
32
37
38namespace func_sketch::math {
39
47template <typename FunctionType,
48 AcceptableTypesSpec... AcceptableTypesPerArgument>
50public:
58 template <typename InputFunctionType>
59 GeneralMathFunction(std::string name, InputFunctionType&& function)
60 : name_(std::move(name)),
61 function_(std::forward<InputFunctionType>(function)) {}
62
68 [[nodiscard]] std::string_view name() const noexcept { return name_; }
69
76 void operator()(const std::vector<Number>& args, Number& result) const {
77 constexpr std::size_t num_args = sizeof...(AcceptableTypesPerArgument);
78 if (args.size() != num_args) {
79 throw InvalidExpressionException(fmt::format(
80 "{} function requires exactly {} arguments. Actual: {}.", name_,
81 num_args, args.size()));
82 }
83 operate_impl(args, result, std::make_index_sequence<num_args>{});
84 }
85
86private:
88 using AcceptableTypesTuples = std::tuple<AcceptableTypesPerArgument...>;
89
97 template <std::size_t... Indices>
98 void operate_impl(const std::vector<Number>& args, Number& result,
99 std::index_sequence<Indices...> /*indices*/) const {
100 std::visit(
101 [this, &result](const auto&... actual_args) {
102 constexpr bool is_all_acceptable =
103 (is_acceptable<std::decay_t<decltype(actual_args)>,
104 Indices>() &&
105 ...);
106 if constexpr (is_all_acceptable) {
108 std::decay_t<decltype(actual_args)>, Indices>(
109 actual_args)...);
110 } else {
111 constexpr std::size_t first_unacceptable_index =
113 is_acceptable<std::decay_t<decltype(actual_args)>,
114 Indices>()...);
115 using FirstUnacceptableType = std::decay_t<
116 decltype(std::get<first_unacceptable_index>(
117 std::forward_as_tuple(actual_args...)))>;
118 throw InvalidExpressionException(fmt::format(
119 "{} function can not accept {} for the {}-th argument.",
121 first_unacceptable_index + 1));
122 }
123 },
124 args[Indices]...);
125 }
126
138 template <typename GivenType, std::size_t Index>
139 [[nodiscard]] static constexpr bool is_acceptable() {
140 using AcceptableTypes =
141 std::tuple_element_t<Index, AcceptableTypesTuples>;
142 return !std::is_same_v<
143 typename AcceptableTypes::template SelectTypeToUse<GivenType>,
145 }
146
156 template <typename GivenType, std::size_t Index>
157 [[nodiscard]] static auto convert_to_acceptable_type(
158 const GivenType& value) {
159 using AcceptableTypes =
160 std::tuple_element_t<Index, AcceptableTypesTuples>;
161 return static_cast<
162 AcceptableTypes::template SelectTypeToUse<GivenType>>(value);
163 }
164
174 template <std::same_as<bool>... T>
175 [[nodiscard]] static constexpr std::size_t get_first_false(
176 bool first, T... remaining) {
177 if (!first) {
178 return 0;
179 }
180 return 1 + get_first_false(remaining...);
181 }
182
188 [[nodiscard]] static constexpr std::size_t get_first_false() { return 0; }
189
191 std::string name_;
192
194 FunctionType function_;
195};
196
197namespace details {
198
205template <typename Type>
206struct IsAcceptableTypesTuple : std::false_type {};
207
214template <AcceptableTypesSpec... Types>
215struct IsAcceptableTypesTuple<std::tuple<Types...>> : std::true_type {};
216
223template <typename Type>
225
237template <details::AcceptableTypesTupleType AcceptableTypesTuple,
238 typename FunctionType, std::size_t... Indices>
239[[nodiscard]] auto make_general_math_function_impl(std::string name,
240 FunctionType&& function, std::index_sequence<Indices...> /*indices*/) {
242 std::tuple_element_t<Indices, AcceptableTypesTuple>...>(
243 std::move(name), std::forward<FunctionType>(function));
244}
245
246} // namespace details
247
258template <details::AcceptableTypesTupleType AcceptableTypesTuple,
259 typename FunctionType>
260[[nodiscard]] auto make_general_math_function(
261 std::string name, FunctionType&& function) {
263 std::move(name), std::forward<FunctionType>(function),
264 std::make_index_sequence<std::tuple_size_v<AcceptableTypesTuple>>{});
265}
266
267} // namespace func_sketch::math
Definition of AcceptableTypes struct.
Class of exceptions of invalid expressions.
Definition exceptions.h:45
Class of general implementation of mathematical functions.
GeneralMathFunction(std::string name, InputFunctionType &&function)
Constructor.
void operate_impl(const std::vector< Number > &args, Number &result, std::index_sequence< Indices... >) const
Operate on scalars (internal implementation).
std::tuple< AcceptableTypesPerArgument... > AcceptableTypesTuples
Type of tuples of acceptable types.
static constexpr bool is_acceptable()
Check whether the given type is acceptable for the argument at the given index.
void operator()(const std::vector< Number > &args, Number &result) const
Operate on scalars.
static constexpr std::size_t get_first_false()
Get the first false. (Variadic template base case).
static auto convert_to_acceptable_type(const GivenType &value)
Convert the given value to an acceptable type for the argument at the given index.
static constexpr std::size_t get_first_false(bool first, T... remaining)
Get the index of the first false value.
std::string_view name() const noexcept
Get the name of the function.
FunctionType function_
Function object to compute numbers.
Definitions of common types.
std::variant< Integer, Real, Complex > Number
Type of numbers.
Concept to check whether a type is func_sketch::math::AcceptableTypes.
Concept to check whether a type is a tuple of func_sketch::math::AcceptableTypes.
Definition of exception classes.
auto make_general_math_function_impl(std::string name, FunctionType &&function, std::index_sequence< Indices... >)
Make a general mathematical function.
auto make_general_math_function(std::string name, FunctionType &&function)
Make a general mathematical function.
Definition of number_type_name constant.
constexpr std::string_view number_type_name
Name of the number type.
Traits struct to handle acceptable number types.
Struct to indicate that there is no acceptable type.
Check whether a type is a tuple of func_sketch::math::AcceptableTypes.