Skip to content

Commit 178fda8

Browse files
authored
Merge pull request #148 from NickUfer/sigmoid_funcs
Add sigmoid(), sigmoid_approx(), sigmoid_affine() and sigmoid_affine_approx() functions
2 parents ad177bf + a88df50 commit 178fda8

File tree

5 files changed

+131
-0
lines changed

5 files changed

+131
-0
lines changed

core/math/math_funcs.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,20 @@ class Math {
759759
}
760760
return p_target;
761761
}
762+
763+
static _ALWAYS_INLINE_ double sigmoid_affine(double p_x, double p_amplitude, double p_y_translation) {
764+
return p_amplitude / (1.0 + ::exp(-p_x)) + p_y_translation;
765+
}
766+
static _ALWAYS_INLINE_ float sigmoid_affine(float p_x, float p_amplitude, float p_y_translation) {
767+
return p_amplitude / (1.0f + expf(-p_x)) + p_y_translation;
768+
}
769+
770+
static _ALWAYS_INLINE_ double sigmoid_affine_approx(double p_x, double p_amplitude, double p_y_translation) {
771+
return p_amplitude * (0.5 + p_x / (4.0 + fabs(p_x))) + p_y_translation;
772+
}
773+
static _ALWAYS_INLINE_ float sigmoid_affine_approx(float p_x, float p_amplitude, float p_y_translation) {
774+
return p_amplitude * (0.5f + p_x / (4.0f + fabsf(p_x))) + p_y_translation;
775+
}
762776
};
763777

764778
#endif // MATH_FUNCS_H

core/variant/variant_utility.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,22 @@ double VariantUtilityFunctions::pingpong(double value, double length) {
641641
return Math::pingpong(value, length);
642642
}
643643

644+
double VariantUtilityFunctions::sigmoid(double x) {
645+
return Math::sigmoid_affine(x, 1.0, 0.0);
646+
}
647+
648+
double VariantUtilityFunctions::sigmoid_approx(double x) {
649+
return Math::sigmoid_affine_approx(x, 1.0, 0.0);
650+
}
651+
652+
double VariantUtilityFunctions::sigmoid_affine(double x, double amplitude, double y_translation) {
653+
return Math::sigmoid_affine(x, amplitude, y_translation);
654+
}
655+
656+
double VariantUtilityFunctions::sigmoid_affine_approx(double x, double amplitude, double y_translation) {
657+
return Math::sigmoid_affine_approx(x, amplitude, y_translation);
658+
}
659+
644660
Variant VariantUtilityFunctions::max(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
645661
if (p_argcount < 2) {
646662
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
@@ -1809,6 +1825,11 @@ void Variant::_register_variant_utility_functions() {
18091825
FUNCBINDR(nearest_po2, sarray("value"), Variant::UTILITY_FUNC_TYPE_MATH);
18101826
FUNCBINDR(pingpong, sarray("value", "length"), Variant::UTILITY_FUNC_TYPE_MATH);
18111827

1828+
FUNCBINDR(sigmoid, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
1829+
FUNCBINDR(sigmoid_approx, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
1830+
FUNCBINDR(sigmoid_affine, sarray("x", "amplitude", "y_translation"), Variant::UTILITY_FUNC_TYPE_MATH);
1831+
FUNCBINDR(sigmoid_affine_approx, sarray("x", "amplitude", "y_translation"), Variant::UTILITY_FUNC_TYPE_MATH);
1832+
18121833
// Random
18131834

18141835
FUNCBIND(randomize, sarray(), Variant::UTILITY_FUNC_TYPE_RANDOM);

core/variant/variant_utility.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ struct VariantUtilityFunctions {
117117
static double clampf(double x, double min, double max);
118118
static int64_t clampi(int64_t x, int64_t min, int64_t max);
119119
static int64_t nearest_po2(int64_t x);
120+
static double sigmoid(double x);
121+
static double sigmoid_approx(double x);
122+
static double sigmoid_affine(double x, double amplitude, double y_translation);
123+
static double sigmoid_affine_approx(double x, double amplitude, double y_translation);
120124
// Random
121125
static void randomize();
122126
static int64_t randi();

doc/classes/@GlobalScope.xml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,6 +1185,84 @@
11851185
[/codeblocks]
11861186
</description>
11871187
</method>
1188+
<method name="sigmoid">
1189+
<return type="float" />
1190+
<param index="0" name="x" type="float" />
1191+
<description>
1192+
Computes the sigmoid for [param x], which maps the input value into the range (0, 1).
1193+
The sigmoid function is defined as:
1194+
[codeblock]
1195+
sigmoid(x) = 1 / (1 + exp(-x))
1196+
[/codeblock]
1197+
This is the most accurate implementation of the sigmoid.
1198+
[codeblock]
1199+
var result = sigmoid(0.0) # result is 0.5
1200+
var result = sigmoid(1.0) # result is approximately 0.7310
1201+
var result = sigmoid(-1.0) # result is approximately 0.2689
1202+
var result = sigmoid(5.0) # result is approximately 0.9933
1203+
[/codeblock]
1204+
[b]Note:[/b] For faster but less accurate approximation, see [method sigmoid_approx].
1205+
</description>
1206+
</method>
1207+
<method name="sigmoid_affine">
1208+
<return type="float" />
1209+
<param index="0" name="x" type="float" />
1210+
<param index="1" name="amplitude" type="float" />
1211+
<param index="2" name="y_translation" type="float" />
1212+
<description>
1213+
Computes an affine-transformed sigmoid for [param x], which allows scaling by [param amplitude] and translation by [param y_translation].
1214+
The affine sigmoid function is defined as:
1215+
[codeblock]
1216+
sigmoid_affine(x, amplitude, y_translation) = (amplitude / (1 + exp(-x))) + y_translation
1217+
[/codeblock]
1218+
This function modifies the standard sigmoid by introducing scaling and vertical translation.
1219+
[codeblock]
1220+
var result = sigmoid_affine(0.0, 1.0, 0.0) # result is 0.5
1221+
var result = sigmoid_affine(1.0, 2.0, -1.0) # result is approximately 0.4621
1222+
var result = sigmoid_affine(-1.0, 3.0, 2.0) # result is approximately 2.8068
1223+
var result = sigmoid_affine(1.0, 2.0, 2.5) # result is approximately 3.9621
1224+
[/codeblock]
1225+
[b]Note:[/b] This is a more accurate but computationally heavier version of the affine sigmoid. For faster approximations, see [method sigmoid_affine_approx].
1226+
</description>
1227+
</method>
1228+
<method name="sigmoid_affine_approx">
1229+
<return type="float" />
1230+
<param index="0" name="x" type="float" />
1231+
<param index="1" name="amplitude" type="float" />
1232+
<param index="2" name="y_translation" type="float" />
1233+
<description>
1234+
Computes an approximation of the affine-transformed sigmoid function for [param x], allowing scaling by [param amplitude] and translation by [param y_translation].
1235+
The approximation function is defined as:
1236+
[codeblock]
1237+
affine_sigmoid_approx(x, amplitude, y_translation) = amplitude * (0.5 + (x / (4 + abs(x)))) + y_translation
1238+
[/codeblock]
1239+
This function approximates the affine sigmoid, offering faster computation at the cost of some precision. It is useful in performance-sensitive environments where both transformation and speed are needed.
1240+
[codeblock]
1241+
var result = sigmoid_affine_approx(0.0, 1.0, 0.0) # result is 0.5
1242+
var result = sigmoid_affine_approx(2.0, 2.0, 1.0) # result is approximately 2.6667
1243+
var result = sigmoid_affine_approx(-1.0, 3.0, 0.5) # result is 1.4
1244+
var result = sigmoid_affine_approx(1.0, 2.0, 2.5) # result is 3.9
1245+
[/codeblock]
1246+
</description>
1247+
</method>
1248+
<method name="sigmoid_approx">
1249+
<return type="float" />
1250+
<param index="0" name="x" type="float" />
1251+
<description>
1252+
Computes an approximation of the sigmoid function for [param x], which maps the input value into the range (0, 1).
1253+
The approximation function is defined as:
1254+
[codeblock]
1255+
sigmoid_approx(x) = 0.5 + (x / (4 + abs(x)))
1256+
[/codeblock]
1257+
This function is faster than the standard [method sigmoid], especially useful in performance-sensitive environments where a balance between accuracy and speed is desired.
1258+
[codeblock]
1259+
var result = sigmoid_approx(0.0) # result is 0.5
1260+
var result = sigmoid_approx(2.0) # result is approximately 0.8333
1261+
var result = sigmoid_approx(-1.0) # result is 0.3
1262+
var result = sigmoid_approx(5.0) # result is approximately 1.0555
1263+
[/codeblock]
1264+
</description>
1265+
</method>
11881266
<method name="sign">
11891267
<return type="Variant" />
11901268
<param index="0" name="x" type="Variant" />

tests/core/math/test_math_funcs.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,20 @@ TEST_CASE_TEMPLATE("[Math] bezier_interpolate", T, float, double) {
641641
CHECK(Math::bezier_interpolate((T)0.0, (T)0.2, (T)0.8, (T)1.0, (T)1.0) == doctest::Approx((T)1.0));
642642
}
643643

644+
TEST_CASE_TEMPLATE("[Math] sigmoid_affine", T, float, double) {
645+
CHECK(Math::sigmoid_affine((T)0.0, (T)1.0, (T)0.0) == doctest::Approx((T)0.5));
646+
CHECK(Math::sigmoid_affine((T)1.0, (T)2.0, (T)-1.0) == doctest::Approx((T)0.4621));
647+
CHECK(Math::sigmoid_affine((T)-1.0, (T)3.0, (T)2.0) == doctest::Approx((T)2.8068));
648+
CHECK(Math::sigmoid_affine((T)1.0, (T)2.0, (T)2.5) == doctest::Approx((T)3.9621));
649+
}
650+
651+
TEST_CASE_TEMPLATE("[Math] sigmoid_affine_approx", T, float, double) {
652+
CHECK(Math::sigmoid_affine_approx((T)0.0, (T)1.0, (T)0.0) == doctest::Approx((T)0.5));
653+
CHECK(Math::sigmoid_affine_approx((T)2.0, (T)2.0, (T)1.0) == doctest::Approx((T)2.6667));
654+
CHECK(Math::sigmoid_affine_approx((T)-1.0, (T)3.0, (T)0.5) == doctest::Approx((T)1.4));
655+
CHECK(Math::sigmoid_affine_approx((T)1.0, (T)2.0, (T)2.5) == doctest::Approx((T)3.9));
656+
}
657+
644658
} // namespace TestMath
645659

646660
#endif // TEST_MATH_FUNCS_H

0 commit comments

Comments
 (0)