const_poly/term.rs
1use crate::function_approximations::*;
2
3/// Enum representing the mathematical function applied to a variable in a term.
4///
5/// Each variant corresponds to a supported unary function that can be applied
6/// to a variable within a polynomial term.
7///
8/// Variants:
9/// - `Identity`: the variable itself (no function applied)
10/// - `Pow(u32)`: power function `x^n` where `n` is the exponent
11/// - `Sin`: sine function
12/// - `Cos`: cosine function
13/// - `Tan`: tangent function
14/// - `Exp`: exponential function (e^x)
15/// - `Ln`: natural logarithm
16/// - `Sqrt`: square root function
17/// - `Arctan`: arctangent function
18/// - `Sinh`: hyperbolic sine function
19/// - `Cosh`: hyperbolic cosine function
20#[derive(Clone, Copy)]
21pub enum VarFunction {
22 Identity, // x
23 Pow(i32), // x^n
24 Sin, // sin(x)
25 Cos, // cos(x)
26 Tan, // tan(x)
27 Exp, // exp(x)
28 Ln, // ln(x)
29 Sqrt, // sqrt(x)
30 Arctan, // arctan(x)
31 Sinh, // sinh(x)
32 Cosh, // cosh(x)
33}
34
35/// Represents a single term in a polynomial with NUM_VARIABLES variables.
36///
37/// A term consists of a coefficient and an array of `VarFunction`s, each
38/// applied to a corresponding variable in the input.
39///
40/// For example, for `NUM_VARIABLES = 2`:
41/// ```
42/// use const_poly::{Term, VarFunction::*};
43/// const TERM: Term<2> = Term::new(3.0, [Sin, Pow(2)]);
44/// ```
45/// represents the term `3 * sin(x_0) * (x_1)^2`.
46#[derive(Copy, Clone)]
47pub struct Term<const NUM_VARIABLES: usize> {
48 coeff: f64,
49 functions: [VarFunction; NUM_VARIABLES],
50}
51
52impl<const NUM_VARIABLES: usize> Term<NUM_VARIABLES> {
53 /// Creates a new `Term` with the specified coefficient and functions.
54 ///
55 /// # Parameters
56 ///
57 /// - `coefficient`: The scalar multiplier for the term.
58 /// - `functions`: An array of `VarFunction`s, one per variable.
59 ///
60 /// # Returns
61 ///
62 /// A new `Term` instance.
63 ///
64 /// # Example
65 ///
66 /// ```
67 /// use const_poly::{Term, VarFunction::*};
68 /// const TERM: Term<2> = Term::new(2.0, [Sin, Pow(3)]);
69 /// ```
70 /// represents the term `2.0 * sin(x_0) * (x_1)^3`.
71 pub const fn new(coefficient: f64, functions: [VarFunction; NUM_VARIABLES]) -> Self {
72 Self {
73 coeff: coefficient,
74 functions,
75 }
76 }
77
78 /// Evaluates the term for the given variables.
79 ///
80 /// Applies each function in `functions` to the corresponding variable,
81 /// then multiplies all results together with the coefficient.
82 ///
83 /// # Parameters
84 ///
85 /// - `vars`: An array of variables of length `NUM_VARIABLES`.
86 ///
87 /// # Returns
88 ///
89 /// The floating-point result of evaluating the term.
90 ///
91 /// # Example
92 ///
93 /// ```
94 /// use const_poly::{Term, VarFunction::*};
95 /// const TERM: Term<1> = Term::new(2.0, [Sin]);
96 /// const val: f64 = TERM.evaluate([1.57079632679]); // Approx sin(pi/2)
97 /// assert!((val - 2.0).abs() < 1e-6);
98 /// ```
99 pub const fn evaluate(&self, vars: [f64; NUM_VARIABLES]) -> f64 {
100 let mut result = self.coeff;
101 let mut i = 0;
102
103 while i < NUM_VARIABLES {
104 let value = match self.functions[i] {
105 VarFunction::Identity => vars[i],
106 VarFunction::Pow(exp) => static_powi(vars[i], exp),
107 VarFunction::Sin => sin_approx(vars[i]),
108 VarFunction::Cos => cos_approx(vars[i]),
109 VarFunction::Tan => tan_approx(vars[i]),
110 VarFunction::Exp => exp_approx(vars[i]),
111 VarFunction::Ln => ln_approx(vars[i]),
112 VarFunction::Sqrt => sqrt_approx(vars[i]),
113 VarFunction::Arctan => arctan_approx(vars[i]),
114 VarFunction::Sinh => sinh_approx(vars[i]),
115 VarFunction::Cosh => cosh_approx(vars[i]),
116 };
117
118 result *= value;
119 i += 1;
120 }
121
122 result
123 }
124}