From 7c916637baf07cd78f271b820471772d315974cf Mon Sep 17 00:00:00 2001 From: tqfx Date: Wed, 25 Sep 2024 19:48:59 +0800 Subject: [PATCH] create regress_simple for Rust --- include/a/regress_simple.h | 26 +++++++++----- src/lib.rs | 86 ++++++++++++++++++++++++++++++++++++++++++++++ src/regress_simple.c | 18 ++++++++-- test/regress_simple.h | 2 +- tests/regress_simple.rs | 12 +++++++ 5 files changed, 132 insertions(+), 12 deletions(-) create mode 100644 tests/regress_simple.rs diff --git a/include/a/regress_simple.h b/include/a/regress_simple.h index 338ca0a..611cc19 100644 --- a/include/a/regress_simple.h +++ b/include/a/regress_simple.h @@ -46,7 +46,7 @@ A_EXTERN a_float a_regress_simple_eval(a_regress_simple const *ctx, a_float val) A_EXTERN a_float a_regress_simple_evar(a_regress_simple const *ctx, a_float val); /*! - @brief ordinary least squares method for simple linear regression + @brief ordinary least squares for simple linear regression @param[in,out] ctx points to an instance of simple linear regression @param[in] n number of samples, x[n], y[n] @param[in] x predictor data, specified as a numeric matrix @@ -54,16 +54,18 @@ A_EXTERN a_float a_regress_simple_evar(a_regress_simple const *ctx, a_float val) @param[in] x_mean mean of predictor data @param[in] y_mean mean of response data */ -A_EXTERN void a_regress_simple_olsm_(a_regress_simple *ctx, a_size n, a_float const *x, a_float const *y, a_float x_mean, a_float y_mean); +A_EXTERN void a_regress_simple_ols_(a_regress_simple *ctx, a_size n, a_float const *x, a_float const *y, a_float x_mean, a_float y_mean); +A_EXTERN void a_regress_simple_olsx(a_regress_simple *ctx, a_size n, a_float const *x, a_float const *y, a_float x_mean); +A_EXTERN void a_regress_simple_olsy(a_regress_simple *ctx, a_size n, a_float const *x, a_float const *y, a_float y_mean); /*! - @brief ordinary least squares method for simple linear regression + @brief ordinary least squares for simple linear regression @param[in,out] ctx points to an instance of simple linear regression @param[in] n number of samples, x[n], y[n] @param[in] x predictor data, specified as a numeric matrix @param[in] y response data, specified as a numeric vector */ -A_EXTERN void a_regress_simple_olsm(a_regress_simple *ctx, a_size n, a_float const *x, a_float const *y); +A_EXTERN void a_regress_simple_ols(a_regress_simple *ctx, a_size n, a_float const *x, a_float const *y); /*! @brief zeroing for simple linear regression @@ -95,13 +97,21 @@ struct a_regress_simple { return a_regress_simple_eval(this, val); } - A_INLINE void olsm(a_size n, a_float const *x, a_float const *y, a_float x_mean, a_float y_mean) + A_INLINE void ols(a_size n, a_float const *x, a_float const *y, a_float x_mean, a_float y_mean) { - a_regress_simple_olsm_(this, n, x, y, x_mean, y_mean); + a_regress_simple_ols_(this, n, x, y, x_mean, y_mean); } - A_INLINE void olsm(a_size n, a_float const *x, a_float const *y) + A_INLINE void olsx(a_size n, a_float const *x, a_float const *y, a_float x_mean) { - a_regress_simple_olsm(this, n, x, y); + a_regress_simple_olsx(this, n, x, y, x_mean); + } + A_INLINE void olsy(a_size n, a_float const *x, a_float const *y, a_float y_mean) + { + a_regress_simple_olsy(this, n, x, y, y_mean); + } + A_INLINE void ols(a_size n, a_float const *x, a_float const *y) + { + a_regress_simple_ols(this, n, x, y); } A_INLINE void zero() { a_regress_simple_zero(this); } #endif /* __cplusplus */ diff --git a/src/lib.rs b/src/lib.rs index f88fbd2..e7047f3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -862,6 +862,92 @@ impl pid_neuro { } } +/// simple linear regression +#[repr(C)] +pub struct regress_simple { + /// regression coefficient + pub coef: float, + /// intercept + pub bias: float, +} + +extern "C" { + fn a_regress_simple_eval(ctx: *const regress_simple, val: float) -> float; + fn a_regress_simple_evar(ctx: *const regress_simple, val: float) -> float; + fn a_regress_simple_ols_( + ctx: *mut regress_simple, + n: usize, + x: *const float, + y: *const float, + x_mean: float, + y_mean: float, + ); + fn a_regress_simple_olsx( + ctx: *mut regress_simple, + n: usize, + x: *const float, + y: *const float, + x_mean: float, + ); + fn a_regress_simple_olsy( + ctx: *mut regress_simple, + n: usize, + x: *const float, + y: *const float, + y_mean: float, + ); + fn a_regress_simple_ols(ctx: *mut regress_simple, n: usize, x: *const float, y: *const float); + fn a_regress_simple_zero(ctx: *mut regress_simple); +} + +impl regress_simple { + /// initialize for simple linear regression + #[inline(always)] + pub fn new(coef: float, bias: float) -> Self { + Self { coef, bias } + } + /// calculate predicted value for simple linear regression + #[inline(always)] + pub fn eval(&self, val: float) -> float { + unsafe { a_regress_simple_eval(self, val) } + } + /// calculate predicted value for simple linear regression + #[inline(always)] + pub fn evar(&self, val: float) -> float { + unsafe { a_regress_simple_evar(self, val) } + } + /// ordinary least squares for simple linear regression + #[inline(always)] + pub fn ols_(&mut self, x: &[float], y: &[float], x_mean: float, y_mean: float) -> &mut Self { + unsafe { a_regress_simple_ols_(self, x.len(), x.as_ptr(), y.as_ptr(), x_mean, y_mean) }; + self + } + /// ordinary least squares for simple linear regression + #[inline(always)] + pub fn olsx(&mut self, x: &[float], y: &[float], x_mean: float) -> &mut Self { + unsafe { a_regress_simple_olsx(self, x.len(), x.as_ptr(), y.as_ptr(), x_mean) }; + self + } + /// ordinary least squares for simple linear regression + #[inline(always)] + pub fn olsy(&mut self, x: &[float], y: &[float], y_mean: float) -> &mut Self { + unsafe { a_regress_simple_olsy(self, x.len(), x.as_ptr(), y.as_ptr(), y_mean) }; + self + } + /// ordinary least squares for simple linear regression + #[inline(always)] + pub fn ols(&mut self, x: &[float], y: &[float]) -> &mut Self { + unsafe { a_regress_simple_ols(self, x.len(), x.as_ptr(), y.as_ptr()) }; + self + } + /// zeroing for simple linear regression + #[inline(always)] + pub fn zero(&mut self) -> &mut Self { + unsafe { a_regress_simple_zero(self) }; + self + } +} + /// transfer function #[repr(C)] pub struct tf { diff --git a/src/regress_simple.c b/src/regress_simple.c index 8286636..f43de34 100644 --- a/src/regress_simple.c +++ b/src/regress_simple.c @@ -16,7 +16,7 @@ a_float a_regress_simple_evar(a_regress_simple const *ctx, a_float val) return (val - ctx->bias) / ctx->coef; } -void a_regress_simple_olsm_(a_regress_simple *ctx, a_size n, a_float const *x, a_float const *y, a_float x_mean, a_float y_mean) +void a_regress_simple_ols_(a_regress_simple *ctx, a_size n, a_float const *x, a_float const *y, a_float x_mean, a_float y_mean) { a_float num = 0, den = 0; for (; n; --n) @@ -30,11 +30,23 @@ void a_regress_simple_olsm_(a_regress_simple *ctx, a_size n, a_float const *x, a ctx->bias = y_mean - ctx->coef * x_mean; } -void a_regress_simple_olsm(a_regress_simple *ctx, a_size n, a_float const *x, a_float const *y) +void a_regress_simple_olsx(a_regress_simple *ctx, a_size n, a_float const *x, a_float const *y, a_float x_mean) +{ + a_float const y_mean = a_float_mean(y, n); + a_regress_simple_ols_(ctx, n, x, y, x_mean, y_mean); +} + +void a_regress_simple_olsy(a_regress_simple *ctx, a_size n, a_float const *x, a_float const *y, a_float y_mean) +{ + a_float const x_mean = a_float_mean(x, n); + a_regress_simple_ols_(ctx, n, x, y, x_mean, y_mean); +} + +void a_regress_simple_ols(a_regress_simple *ctx, a_size n, a_float const *x, a_float const *y) { a_float const x_mean = a_float_mean(x, n); a_float const y_mean = a_float_mean(y, n); - a_regress_simple_olsm_(ctx, n, x, y, x_mean, y_mean); + a_regress_simple_ols_(ctx, n, x, y, x_mean, y_mean); } void a_regress_simple_zero(a_regress_simple *ctx) diff --git a/test/regress_simple.h b/test/regress_simple.h index ba2827f..0603710 100644 --- a/test/regress_simple.h +++ b/test/regress_simple.h @@ -42,7 +42,7 @@ int main(int argc, char *argv[]) // NOLINT(misc-definitions-in-headers) a_regress_simple ctx; a_regress_simple_init(&ctx, 0, 0); - a_regress_simple_olsm(&ctx, n, x, y); + a_regress_simple_ols(&ctx, n, x, y); for (unsigned int i = 0; i < n; ++i) { diff --git a/tests/regress_simple.rs b/tests/regress_simple.rs new file mode 100644 index 0000000..aaca687 --- /dev/null +++ b/tests/regress_simple.rs @@ -0,0 +1,12 @@ +#[test] +fn regress_simple() { + let mut regress = liba::regress_simple::new(0.0, 0.0); + let x = [0.0, 2.0, 4.0, 6.0, 8.0]; + let y = [1.0, 2.0, 3.0, 4.0, 5.0]; + regress.ols(&x, &y); + std::println!("y={}x+{}", regress.coef, regress.bias); + for i in 0..x.len() { + std::println!("{},{}", regress.evar(y[i]), regress.eval(x[i])); + } + regress.zero(); +} -- 2.11.4.GIT