MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Tendency.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <glm/glm.hpp>
4
5namespace MayaFlux::Kinesis {
6
7/**
8 * @struct Tendency
9 * @brief Typed, composable, stateless callable from domain D to range R
10 * @tparam D Domain type (input)
11 * @tparam R Range type (output)
12 *
13 * Pure mathematical substrate expressing directional pull: a function
14 * that maps a point in the domain to a value in the range. No internal
15 * state, no history, no Vulkan awareness, no analog-era vocabulary.
16 * Parameters that evolve over time are Datum<T> instances captured
17 * in the lambda at construction.
18 *
19 * Composition is handled by free functions in this namespace.
20 */
21template <typename D, typename R>
22struct Tendency {
23 std::function<R(const D&)> fn;
24
25 /**
26 * @brief Evaluate the tendency at a point in the domain
27 * @param d Domain value
28 * @return Range value
29 */
30 R operator()(const D& d) const { return fn(d); }
31
32 /**
33 * @brief Named evaluation (identical to operator())
34 * @param d Domain value
35 * @return Range value
36 */
37 [[nodiscard]] R evaluate(const D& d) const { return fn(d); }
38};
39
40// =========================================================================
41// Type aliases
42// =========================================================================
43
49
50// =========================================================================
51// Composition
52// =========================================================================
53
54/**
55 * @brief Combine two tendencies with a binary operation on their outputs
56 * @tparam D Shared domain type
57 * @tparam R Shared range type
58 * @tparam BinaryOp Callable: (R, R) -> R
59 * @param a First tendency
60 * @param b Second tendency
61 * @param op Binary combiner
62 * @return Combined tendency
63 */
64template <typename D, typename R, typename BinaryOp>
66{
67 return { .fn = [a, b, op](const D& d) -> R {
68 return op(a(d), b(d));
69 } };
70}
71
72/**
73 * @brief Sequential composition: evaluate first, feed result into second
74 * @tparam A Input domain
75 * @tparam B Intermediate type
76 * @tparam C Output range
77 * @param first A -> B tendency
78 * @param second B -> C tendency
79 * @return Composed A -> C tendency
80 */
81template <typename A, typename B, typename C>
83{
84 return { .fn = [first, second](const A& a) -> C {
85 return second(first(a));
86 } };
87}
88
89/**
90 * @brief Uniform scaling of a scalar-output tendency
91 * @tparam D Domain type
92 * @param t Source tendency
93 * @param factor Scale multiplier
94 * @return Scaled tendency
95 */
96template <typename D>
98{
99 return { .fn = [t, factor](const D& d) -> float {
100 return t(d) * factor;
101 } };
102}
103
104/**
105 * @brief Uniform scaling of a vector field
106 * @param t Source tendency
107 * @param factor Scale multiplier
108 * @return Scaled tendency
109 */
110inline VectorField scale(const VectorField& t, float factor)
111{
112 return { .fn = [t, factor](const glm::vec3& d) -> glm::vec3 {
113 return t(d) * factor;
114 } };
115}
116
117/**
118 * @brief Clamp scalar output to [lo, hi]
119 * @tparam D Domain type
120 * @param t Source tendency
121 * @param lo Lower bound
122 * @param hi Upper bound
123 * @return Clamped tendency
124 */
125template <typename D>
126Tendency<D, float> clamp(const Tendency<D, float>& t, float lo, float hi)
127{
128 return { .fn = [t, lo, hi](const D& d) -> float {
129 return std::clamp(t(d), lo, hi);
130 } };
131}
132
133/**
134 * @brief Zero output below threshold, pass through above
135 * @tparam D Domain type
136 * @param t Source tendency
137 * @param thresh Threshold value
138 * @return Thresholded tendency
139 */
140template <typename D>
142{
143 return { .fn = [t, thresh](const D& d) -> float {
144 float v = t(d);
145 return v < thresh ? 0.0F : v;
146 } };
147}
148
149/**
150 * @brief Negate a scalar-output tendency
151 * @tparam D Domain type
152 * @param t Source tendency
153 * @return Negated tendency
154 */
155template <typename D>
157{
158 return { .fn = [t](const D& d) -> float {
159 return -t(d);
160 } };
161}
162
163/**
164 * @brief Negate all components of a vector field
165 * @param t Source tendency
166 * @return Negated tendency
167 */
169{
170 return { .fn = [t](const glm::vec3& d) -> glm::vec3 {
171 return -t(d);
172 } };
173}
174
175/**
176 * @brief Interpolate between two tendencies controlled by a weight tendency
177 * @tparam D Shared domain type
178 * @param a First tendency (weight 0.0)
179 * @param b Second tendency (weight 1.0)
180 * @param weight D -> float tendency producing interpolation factor
181 * @return Blended tendency
182 */
183template <typename D>
185{
186 return { .fn = [a, b, weight](const D& d) -> float {
187 float w = weight(d);
188 return a(d) * (1.0F - w) + b(d) * w;
189 } };
190}
191
192/**
193 * @brief Select between two tendencies based on a predicate tendency
194 * @tparam D Shared domain type
195 * @tparam R Shared range type
196 * @param predicate D -> float tendency (positive selects then_t, non-positive selects else_t)
197 * @param then_t Tendency selected when predicate > 0
198 * @param else_t Tendency selected when predicate <= 0
199 * @return Conditional tendency
200 */
201template <typename D, typename R>
202Tendency<D, R> select(const Tendency<D, float>& predicate, const Tendency<D, R>& then_t, const Tendency<D, R>& else_t)
203{
204 return { .fn = [predicate, then_t, else_t](const D& d) -> R {
205 return predicate(d) > 0.0F ? then_t(d) : else_t(d);
206 } };
207}
208
209} // namespace MayaFlux::Kinesis
size_t a
double weight
size_t b
Tendency< D, float > invert(const Tendency< D, float > &t)
Negate a scalar-output tendency.
Definition Tendency.hpp:156
Tendency< D, float > threshold(const Tendency< D, float > &t, float thresh)
Zero output below threshold, pass through above.
Definition Tendency.hpp:141
Tendency< A, C > chain(const Tendency< A, B > &first, const Tendency< B, C > &second)
Sequential composition: evaluate first, feed result into second.
Definition Tendency.hpp:82
Tendency< D, float > clamp(const Tendency< D, float > &t, float lo, float hi)
Clamp scalar output to [lo, hi].
Definition Tendency.hpp:126
Tendency< D, R > select(const Tendency< D, float > &predicate, const Tendency< D, R > &then_t, const Tendency< D, R > &else_t)
Select between two tendencies based on a predicate tendency.
Definition Tendency.hpp:202
Tendency< D, float > scale(const Tendency< D, float > &t, float factor)
Uniform scaling of a scalar-output tendency.
Definition Tendency.hpp:97
Tendency< D, R > combine(const Tendency< D, R > &a, const Tendency< D, R > &b, BinaryOp op)
Combine two tendencies with a binary operation on their outputs.
Definition Tendency.hpp:65
Tendency< D, float > lerp(const Tendency< D, float > &a, const Tendency< D, float > &b, const Tendency< D, float > &weight)
Interpolate between two tendencies controlled by a weight tendency.
Definition Tendency.hpp:184
std::function< R(const D &)> fn
Definition Tendency.hpp:23
R operator()(const D &d) const
Evaluate the tendency at a point in the domain.
Definition Tendency.hpp:30
R evaluate(const D &d) const
Named evaluation (identical to operator())
Definition Tendency.hpp:37
Typed, composable, stateless callable from domain D to range R.
Definition Tendency.hpp:22