Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
255 changes: 213 additions & 42 deletions specs/tri/math/statistics.t27
Original file line number Diff line number Diff line change
Expand Up @@ -10,67 +10,238 @@ module TriStatistics;
// 3. Core Functions
// ═══════════════════════════════════════════════════════════

// mean(values: []f64) → void
fn mean(values: []f64) -> void {
// TODO: Implement from .tri spec
// mean(values: []f64) → f64
fn mean(values: []f64) -> f64 {
var sum: f64 = 0.0;
for (i in 0..values.len) {
sum += values[i];
}
return sum / f64(values.len);
}

// variance(values: []f64) → void
fn variance(values: []f64) -> void {
// TODO: Implement from .tri spec
// variance(values: []f64) → f64
fn variance(values: []f64) -> f64 {
if (values.len == 0) return 0.0;

var mean_val = mean(values);
var sum_sq: f64 = 0.0;
for (i in 0..values.len) {
sum_sq += (values[i] - mean_val) * (values[i] - mean_val);
}
return sum_sq / f64(values.len);
}

// std_dev(values: []f64) → void
fn std_dev(values: []f64) -> void {
// TODO: Implement from .tri spec
// std_dev(values: []f64) → f64
fn std_dev(values: []f64) -> f64 {
return math.sqrt(variance(values));
}

// median(allocator: std.mem.Allocator) → void
fn median(allocator: std.mem.Allocator) -> void {
// TODO: Implement from .tri spec
// median(allocator: std.mem.Allocator, values: []f64) → f64
fn median(allocator: std.mem.Allocator, values: []f64) -> f64 {
if (values.len == 0) return 0.0;

var sorted_values: []f64 = values;

// Simple bubble sort for small datasets
for (i in 0..sorted_values.len) {
for (j in i+1..sorted_values.len) {
if (sorted_values[i] > sorted_values[j]) {
var temp = sorted_values[i];
sorted_values[i] = sorted_values[j];
sorted_values[j] = temp;
}
}
}

var mid = sorted_values.len / 2;
if (sorted_values.len % 2 == 1) {
return sorted_values[mid];
} else {
return (sorted_values[mid - 1] + sorted_values[mid]) / 2.0;
}
}

// percentile(allocator: std.mem.Allocator) → void
fn percentile(allocator: std.mem.Allocator) -> void {
// TODO: Implement from .tri spec
// percentile(allocator: std.mem.Allocator, values: []f64, p: f64) → f64
fn percentile(allocator: std.mem.Allocator, values: []f64, p: f64) -> f64 {
if (values.len == 0) return 0.0;
if (p < 0.0 or p > 100.0) return 0.0;

var sorted_values: []f64 = values;

// Simple bubble sort for small datasets
for (i in 0..sorted_values.len) {
for (j in i+1..sorted_values.len) {
if (sorted_values[i] > sorted_values[j]) {
var temp = sorted_values[i];
sorted_values[i] = sorted_values[j];
sorted_values[j] = temp;
}
}
}

var index = (p / 100.0) * f64(sorted_values.len - 1);
var lower_idx = math.floor(index);
var upper_idx = math.ceil(index);
var weight = index - lower_idx;

if (lower_idx == upper_idx) {
return sorted_values[lower_idx];
} else {
return sorted_values[lower_idx] * (1.0 - weight) + sorted_values[upper_idx] * weight;
}
}

// correlation(x: []f64) → void
fn correlation(x: []f64) -> void {
// TODO: Implement from .tri spec
// correlation(x: []f64, y: []f64) → f64
fn correlation(x: []f64, y: []f64) -> f64 {
if (x.len != y.len or x.len == 0) return 0.0;

var mean_x = mean(x);
var mean_y = mean(y);

var numerator: f64 = 0.0;
var sum_sq_x: f64 = 0.0;
var sum_sq_y: f64 = 0.0;

for (i in 0..x.len) {
var diff_x = x[i] - mean_x;
var diff_y = y[i] - mean_y;
numerator += diff_x * diff_y;
sum_sq_x += diff_x * diff_x;
sum_sq_y += diff_y * diff_y;
}

var denominator = math.sqrt(sum_sq_x * sum_sq_y);
if (denominator == 0.0) return 0.0;

return numerator / denominator;
}

// ═══════════════════════════════════════════════════════════
// TDD: Tests (from .tri behaviors)
// ═══════════════════════════════════════════════════════════

test mean_basic_case
given input = default_input()
when result = mean(input)
then result != undefined
test "mean_basic_case" {
var input = default_input();
var result = mean(input);
assert(result != undefined);
}

test "variance_basic_case" {
var input = default_input();
var result = variance(input);
assert(result != undefined);
}

test "std_dev_basic_case" {
var input = default_input();
var result = std_dev(input);
assert(result != undefined);
}

test "median_basic_case" {
var input = default_input();
var result = median(default_allocator(), input);
assert(result != undefined);
}

test "percentile_basic_case" {
var input = default_input();
var result = percentile(default_allocator(), input, 50.0);
assert(result != undefined);
}

test "correlation_basic_case" {
var x = default_input();
var y = default_input();
var result = correlation(x, y);
assert(result != undefined);
}

test "mean_calculates_correctly" {
var values = [1.0, 2.0, 3.0, 4.0, 5.0];
var result = mean(values);
assert(result == 3.0);
}

test "variance_calculates_correctly" {
var values = [2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0];
var result = variance(values);
assert(result == 4.0);
}

test "std_dev_calculates_correctly" {
var values = [1.0, 2.0, 3.0, 4.0, 5.0];
var result = std_dev(values);
assert(result == math.sqrt(2.0));
}

test "median_odd_number" {
var values = [1.0, 3.0, 2.0, 5.0, 4.0];
var result = median(default_allocator(), values);
assert(result == 3.0);
}

test "median_even_number" {
var values = [1.0, 2.0, 3.0, 4.0];
var result = median(default_allocator(), values);
assert(result == 2.5);
}

test "median_empty" {
var values: []f64 = [];
var result = median(default_allocator(), values);
assert(result == 0.0);
}

test "percentile_50th" {
var values = [1.0, 2.0, 3.0, 4.0, 5.0];
var result = percentile(default_allocator(), values, 50.0);
assert(result == 3.0);
}

test "percentile_25th" {
var values = [1.0, 2.0, 3.0, 4.0, 5.0];
var result = percentile(default_allocator(), values, 25.0);
assert(result == 2.0);
}

test variance_basic_case
given input = default_input()
when result = variance(input)
then result != undefined
test "percentile_empty" {
var values: []f64 = [];
var result = percentile(default_allocator(), values, 50.0);
assert(result == 0.0);
}

test std_dev_basic_case
given input = default_input()
when result = std_dev(input)
then result != undefined
test "correlation_perfect_positive" {
var x = [1.0, 2.0, 3.0, 4.0, 5.0];
var y = [2.0, 4.0, 6.0, 8.0, 10.0];
var result = correlation(x, y);
assert(result == 1.0);
}

test median_basic_case
given input = default_input()
when result = median(input)
then result != undefined
test "correlation_perfect_negative" {
var x = [1.0, 2.0, 3.0, 4.0, 5.0];
var y = [10.0, 8.0, 6.0, 4.0, 2.0];
var result = correlation(x, y);
assert(result == -1.0);
}

test percentile_basic_case
given input = default_input()
when result = percentile(input)
then result != undefined
test "correlation_no_correlation" {
var x = [1.0, 2.0, 3.0, 4.0, 5.0];
var y = [3.0, 1.0, 4.0, 2.0, 5.0];
var result = correlation(x, y);
assert(result >= -1.0 and result <= 1.0);
}

test correlation_basic_case
given input = default_input()
when result = correlation(input)
then result != undefined
test "correlation_different_lengths" {
var x = [1.0, 2.0, 3.0];
var y = [1.0, 2.0];
var result = correlation(x, y);
assert(result == 0.0);
}

test "correlation_empty" {
var x: []f64 = [];
var y: []f64 = [];
var result = correlation(x, y);
assert(result == 0.0);
}