Skip to content

About

C implementation of linear regression algorithm.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Multidimensional Linear Regression in C

A small C11 program that fits a linear model with batch gradient descent. It reads a CSV of input features plus a target, then prints mean squared error and the current weights after every epoch.

The binary is a trainer, not a library. There is no dependency beyond a C compiler and the math library. Sample sets for one and two features ship in the repo.

Features

  • One to several input features (compile-time cap is MAX_FEATURES in regression_utils.h)
  • Batch gradient descent on mean squared error, with a caller-supplied learning rate
  • CSV loader that stores data feature-major (samples[feature][index])
  • Per-epoch MSE and weight dump on stdout
  • Bounds checks on epochs and learning rate via strtoul / strtof; DIE on allocation failure

Quick Start

Needs gcc and make.

git clone https://github.com/mdelriolanse/c-linear-regression.git
cd c-linear-regression
make

That builds ./regression from main.c, regression_core.c, and regression_io.c (-std=c11 -O2 -Wall -Wextra -lm).

Equivalent without Make:

gcc -Wall -Wextra -std=c11 -O2 -o regression main.c regression_core.c regression_io.c -lm
make clean

There is a minimal make test target: it runs the two example commands below and checks for a clean exit plus at least one epoch: line, catching a broken build without asserting exact numbers.

Usage

./regression <num_epochs> <num_features> <num_samples> <learning_rate> <data_file_path>
Argument Meaning
num_epochs Training iterations. Parsed with strtoul. Accepted range is MIN_EPOCHS–MAX_EPOCHS (1–2500).
num_features Input columns in the CSV, not counting the target. Must be between 1 and MAX_FEATURES (10).
num_samples Rows to read. Must be between 1 and MAX_SAMPLES (1000).
learning_rate Step size α. Parsed with strtof. Accepted range is MIN_LR–MAX_LR (1e-12–1).
data_file_path Path to a CSV with no header row.

The sample CSVs each have 100 rows. A run that actually completed on this tree:

./regression 20 1 100 0.0001 singledim_data.csv
./regression 20 2 100 0.0001 multidim_data.csv

initialize_training_config and initialize_dataloader now allow values up to and including the documented maxima (2500 epochs, 10 features, 1000 samples); the 20-epoch commands above are the ones that were run for the output in this README.

Data Format

Each line is feature1,feature2,...,featureN,output. No header. The last field is the label. The parser uses strtok and atof.

1,2.14
2,3.88
3,6.11
1,2,3.14
2,3,5.88
3,4,8.11

singledim_data.csv is 100 pairs. multidim_data.csv is 100 rows of two inputs plus a label. In the two-feature file, the second input is always the first plus one.

Sample Output

./regression 20 1 100 0.0001 singledim_data.csv (trimmed):

Initializing 20 epochs
Initializing 0.000100 learning rate in training configuration
singledim_data.csv
Using 1 features
Using 100 samples
epoch: 1 - mse: 1.354464e+04
weights: w0=1.353932e+00 - bias: 2.020916e-02
epoch: 8 - mse: 5.628254e-03
weights: w0=2.000103e+00 - bias: 2.985244e-02
epoch: 20 - mse: 3.794078e-03
weights: w0=2.000341e+00 - bias: 2.985298e-02

./regression 20 2 100 0.0001 multidim_data.csv (trimmed):

Initializing 20 epochs
Initializing 0.000100 learning rate in training configuration
multidim_data.csv
Using 2 features
Using 100 samples
epoch: 1 - mse: 1.604226e+04
weights: w0=1.472700e+00 w1=1.495039e+00 - bias: 2.233916e-02
epoch: 8 - mse: 1.344831e+01
weights: w0=1.070359e+00 w1=1.088807e+00 - bias: 1.844792e-02
epoch: 20 - mse: 1.341520e+01
weights: w0=1.068919e+00 w1=1.090992e+00 - bias: 2.207305e-02

The one-feature set is close to y = 2x. The two-feature set is collinear, so the split between w0 and w1 is not unique and MSE levels off near 13.4.

Project Structure

c-linear-regression/
├── Makefile
├── main.c                 CLI, argument order, trainer entry
├── regression_core.c      Parameters, forward/backward pass, train loop
├── regression_io.c        CSV parser and epoch / learning-rate / path checks
├── regression_utils.h     Caps, structs, prototypes, DIE macro
├── singledim_data.csv     100 rows, 1 feature
├── multidim_data.csv      100 rows, 2 features
├── test_smoke.sh          Smoke test for `make test`
└── LICENSE                Apache License 2.0

Configuration

Compile-time caps live in regression_utils.h. Learning rate is not taken from the leftover LEARNING_RATE define; main reads it from argv. All caps below are inclusive: a value equal to the maximum is accepted.

Macro Value Role
MIN_EPOCHS / MAX_EPOCHS 1 / 2500 Epoch validator
MIN_LR / MAX_LR 1e-12 / 1 Learning-rate validator
MAX_SAMPLES 1000 Sample-count check in main
MAX_FEATURES 10 Feature-count check in main
PATH_BUF_LEN 256 Path copy buffer
LEARNING_RATE 0.0001 Defined, unused by main

Algorithm

The model is

y_hat = w1*x1 + ... + wn*xn + b

Weights and bias start at zero. Each epoch:

  1. Forward: predict every sample, accumulate MSE, the sum of residuals, and per-feature Σ (y_hat - y) * xj.
  2. Backward: wj -= α * (2 / n) * Σ (y_hat - y) * xj, and the same form for the bias without xj.

Time per run is O(epochs × features × samples). Storage is one float column per feature plus the label vector.

Contributing

Open an issue or a pull request against this repository. There is no separate contributor guide; make test runs the available smoke test.

License

Apache License 2.0. See LICENSE.

About

C implementation of linear regression algorithm.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages