Skip to content

Commit 271355c

Browse files
committed
linreg: Split core C to separate file
1 parent 2571a73 commit 271355c

2 files changed

Lines changed: 98 additions & 96 deletions

File tree

src/emlearn_linreg/eml_linreg.c

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
2+
#include <math.h>
3+
4+
// ElasticNet implementation (embedded from linreg.c)
5+
typedef struct {
6+
float* weights;
7+
float* weight_gradients;
8+
float bias;
9+
uint16_t n_features;
10+
float l1_ratio;
11+
float alpha;
12+
float learning_rate;
13+
} elastic_net_model_t;
14+
15+
// Soft thresholding function for L1 penalty
16+
static float soft_threshold(float x, float threshold) {
17+
if (x > threshold) {
18+
return x - threshold;
19+
} else if (x < -threshold) {
20+
return x + threshold;
21+
} else {
22+
return 0.0f;
23+
}
24+
}
25+
26+
// Calculate prediction for a single sample
27+
static float predict_sample(const elastic_net_model_t* model, const float* features) {
28+
float prediction = model->bias;
29+
for (uint16_t i = 0; i < model->n_features; i++) {
30+
prediction += model->weights[i] * features[i];
31+
}
32+
return prediction;
33+
}
34+
35+
// Single iteration of gradient descent
36+
static void elastic_net_iterate(elastic_net_model_t* model,
37+
const float* X,
38+
const float* y,
39+
uint16_t n_samples) {
40+
41+
// Initialize gradients buffer to zero
42+
memset(model->weight_gradients, 0, model->n_features * sizeof(float));
43+
float bias_gradient = 0.0f;
44+
45+
// Forward pass and gradient calculation
46+
for (uint16_t i = 0; i < n_samples; i++) {
47+
// Calculate prediction
48+
float prediction = predict_sample(model, &X[i * model->n_features]);
49+
50+
// Calculate error
51+
float error = prediction - y[i];
52+
53+
// Accumulate gradients
54+
bias_gradient += error;
55+
for (uint16_t j = 0; j < model->n_features; j++) {
56+
model->weight_gradients[j] += error * X[i * model->n_features + j];
57+
}
58+
}
59+
60+
// Average gradients
61+
bias_gradient /= n_samples;
62+
for (uint16_t j = 0; j < model->n_features; j++) {
63+
model->weight_gradients[j] /= n_samples;
64+
}
65+
66+
// Update weights with regularization
67+
for (uint16_t j = 0; j < model->n_features; j++) {
68+
// Add L2 penalty to gradient
69+
float l2_penalty = model->alpha * (1.0f - model->l1_ratio) * model->weights[j];
70+
71+
// Update weight
72+
float new_weight = model->weights[j] - model->learning_rate * (model->weight_gradients[j] + l2_penalty);
73+
74+
// Apply L1 penalty via soft thresholding
75+
float l1_penalty = model->alpha * model->l1_ratio * model->learning_rate;
76+
model->weights[j] = soft_threshold(new_weight, l1_penalty);
77+
}
78+
79+
// Update bias (no regularization on bias)
80+
model->bias -= model->learning_rate * bias_gradient;
81+
}
82+
83+
// Calculate mean squared error
84+
static float elastic_net_mse(const elastic_net_model_t* model,
85+
const float* X,
86+
const float* y,
87+
uint16_t n_samples) {
88+
89+
float mse = 0.0f;
90+
for (uint16_t i = 0; i < n_samples; i++) {
91+
float prediction = predict_sample(model, &X[i * model->n_features]);
92+
float error = y[i] - prediction;
93+
mse += error * error;
94+
}
95+
return mse / n_samples;
96+
}

src/emlearn_linreg/linreg.c

Lines changed: 2 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
#include <string.h>
55

6+
#include "eml_linreg.c"
7+
68
// memset/memcpy for compatibility
79
#if !defined(__linux__)
810
void *memcpy(void *dst, const void *src, size_t n) {
@@ -13,102 +15,6 @@ void *memset(void *s, int c, size_t n) {
1315
}
1416
#endif
1517

16-
#include <math.h>
17-
18-
// ElasticNet implementation (embedded from linreg.c)
19-
typedef struct {
20-
float* weights;
21-
float* weight_gradients;
22-
float bias;
23-
uint16_t n_features;
24-
float l1_ratio;
25-
float alpha;
26-
float learning_rate;
27-
} elastic_net_model_t;
28-
29-
// Soft thresholding function for L1 penalty
30-
static float soft_threshold(float x, float threshold) {
31-
if (x > threshold) {
32-
return x - threshold;
33-
} else if (x < -threshold) {
34-
return x + threshold;
35-
} else {
36-
return 0.0f;
37-
}
38-
}
39-
40-
// Calculate prediction for a single sample
41-
static float predict_sample(const elastic_net_model_t* model, const float* features) {
42-
float prediction = model->bias;
43-
for (uint16_t i = 0; i < model->n_features; i++) {
44-
prediction += model->weights[i] * features[i];
45-
}
46-
return prediction;
47-
}
48-
49-
// Single iteration of gradient descent
50-
static void elastic_net_iterate(elastic_net_model_t* model,
51-
const float* X,
52-
const float* y,
53-
uint16_t n_samples) {
54-
55-
// Initialize gradients buffer to zero
56-
memset(model->weight_gradients, 0, model->n_features * sizeof(float));
57-
float bias_gradient = 0.0f;
58-
59-
// Forward pass and gradient calculation
60-
for (uint16_t i = 0; i < n_samples; i++) {
61-
// Calculate prediction
62-
float prediction = predict_sample(model, &X[i * model->n_features]);
63-
64-
// Calculate error
65-
float error = prediction - y[i];
66-
67-
// Accumulate gradients
68-
bias_gradient += error;
69-
for (uint16_t j = 0; j < model->n_features; j++) {
70-
model->weight_gradients[j] += error * X[i * model->n_features + j];
71-
}
72-
}
73-
74-
// Average gradients
75-
bias_gradient /= n_samples;
76-
for (uint16_t j = 0; j < model->n_features; j++) {
77-
model->weight_gradients[j] /= n_samples;
78-
}
79-
80-
// Update weights with regularization
81-
for (uint16_t j = 0; j < model->n_features; j++) {
82-
// Add L2 penalty to gradient
83-
float l2_penalty = model->alpha * (1.0f - model->l1_ratio) * model->weights[j];
84-
85-
// Update weight
86-
float new_weight = model->weights[j] - model->learning_rate * (model->weight_gradients[j] + l2_penalty);
87-
88-
// Apply L1 penalty via soft thresholding
89-
float l1_penalty = model->alpha * model->l1_ratio * model->learning_rate;
90-
model->weights[j] = soft_threshold(new_weight, l1_penalty);
91-
}
92-
93-
// Update bias (no regularization on bias)
94-
model->bias -= model->learning_rate * bias_gradient;
95-
}
96-
97-
// Calculate mean squared error
98-
static float elastic_net_mse(const elastic_net_model_t* model,
99-
const float* X,
100-
const float* y,
101-
uint16_t n_samples) {
102-
103-
float mse = 0.0f;
104-
for (uint16_t i = 0; i < n_samples; i++) {
105-
float prediction = predict_sample(model, &X[i * model->n_features]);
106-
float error = y[i] - prediction;
107-
mse += error * error;
108-
}
109-
return mse / n_samples;
110-
}
111-
11218
// MicroPython type for ElasticNet model
11319
typedef struct _mp_obj_elasticnet_model_t {
11420
mp_obj_base_t base;

0 commit comments

Comments
 (0)