Skip to content
Merged
Show file tree
Hide file tree
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
10 changes: 1 addition & 9 deletions build.zig.zon
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.{
.name = .trinity,
.version = "0.15.2",
.version = "0.16.0",
.dependencies = .{
.emsdk = .{
.url = "git+https://github.com/emscripten-core/emsdk?ref=4.0.9#3bcf1dcd01f040f370e10fe673a092d9ed79ebb5",
Expand All @@ -10,14 +10,6 @@
.url = "git+https://github.com/raylib-zig/raylib-zig#cd71c85d571027ac8033357f83b124ee051825b3",
.hash = "raylib_zig-5.6.0-dev-KE8REENOBQC-m5nK7M2b5aKSIubJPbPLUYcRhT7aT3RN",
},
.zodd = .{
.url = "git+https://github.com/CogitatorTech/zodd#main",
.hash = "zodd-0.1.0-alpha.3-TJEk3Y7uAQDOkBXaPV_lynH1rF-eDwf9PnVc13MpPFym",
},
.zig_hdc = .{
.url = "git+https://github.com/gHashTag/zig-hdc#main",
.hash = "zig-hdc-0.1.0-????????????????????????????????????????",
},
},
.paths = .{""},
.fingerprint = 0xa9f69745ba7ed82d,
Expand Down
10 changes: 6 additions & 4 deletions build_minimal.zig
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
const std = @import("std");

pub fn build(b: *std.Build) !void {
pub fn build(b: *std.Build) void {
const optimize = b.standardOptimizeOption(.{});
const target = b.standardTargetOptions(.{});

// Minimal working build - just HSLM CLI first
const hslm_cli = b.addExecutable(.{
.name = "hslm-cli",
const root_mod = b.createModule(.{
.root_source_file = b.path("src/hslm/cli.zig"),
.target = target,
.optimize = optimize,
});
const hslm_cli = b.addExecutable(.{
.name = "hslm-cli",
.root_module = root_mod,
});
b.installArtifact(hslm_cli);

const hslm_run = b.addRunArtifact(hslm_cli);
Expand Down
107 changes: 107 additions & 0 deletions src/brain/angular_gyrus.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
const std = @import("std");

pub const PHI: f64 = 1.6180339887498948482;
pub const PHI_INV: f64 = 1.0 / PHI;
pub const PHI_SQ: f64 = PHI * PHI;
pub const PHI_INV_SQ: f64 = 1.0 / PHI_SQ;
pub const TRINITY: f64 = PHI_SQ + PHI_INV_SQ;

pub const FormatInfo = struct {
name: []const u8,
total_bits: u8,
exp_bits: u8,
mant_bits: u8,
exp_mant_ratio: f64,
phi_distance: f64,
golden_pct: f64,
};

pub const GF16_INFO = FormatInfo{
.name = "GF16",
.total_bits = 16,
.exp_bits = 6,
.mant_bits = 9,
.exp_mant_ratio = 6.0 / 9.0,
.phi_distance = @abs(6.0 / 9.0 - PHI_INV),
.golden_pct = (1.0 - @abs(6.0 / 9.0 - PHI_INV) / PHI_INV) * 100.0,
};

pub const BF16_INFO = FormatInfo{
.name = "BF16",
.total_bits = 16,
.exp_bits = 8,
.mant_bits = 7,
.exp_mant_ratio = 8.0 / 7.0,
.phi_distance = @abs(8.0 / 7.0 - PHI_INV),
.golden_pct = (1.0 - @abs(8.0 / 7.0 - PHI_INV) / PHI_INV) * 100.0,
};

pub const FP16_INFO = FormatInfo{
.name = "FP16",
.total_bits = 16,
.exp_bits = 5,
.mant_bits = 10,
.exp_mant_ratio = 5.0 / 10.0,
.phi_distance = @abs(5.0 / 10.0 - PHI_INV),
.golden_pct = (1.0 - @abs(5.0 / 10.0 - PHI_INV) / PHI_INV) * 100.0,
};

pub fn phiDistance(exp_bits: u8, mant_bits: u8) f64 {
return @abs(@as(f64, @floatFromInt(exp_bits)) / @as(f64, @floatFromInt(mant_bits)) - PHI_INV);
}

pub fn goldenPct(exp_bits: u8, mant_bits: u8) f64 {
const dist = phiDistance(exp_bits, mant_bits);
return (1.0 - dist / PHI_INV) * 100.0;
}

pub fn formatTable(writer: anytype) !void {
try writer.print("\n Format Comparison (phi-distance from 1/phi = {d:.6})\n", .{PHI_INV});
try writer.print(" {s}\n", .{"-" * 72});
try writer.print(" {s:<8} {s:>6} {s:>6} {s:>6} {s:>10} {s:>10}\n", .{ "Format", "Bits", "Exp", "Mant", "e/m ratio", "% golden" });
try writer.print(" {s}\n", .{"-" * 72});

const formats = [_]FormatInfo{ GF16_INFO, BF16_INFO, FP16_INFO };
for (&formats) |f| {
try writer.print(" {s:<8} {d:>6} {d:>6} {d:>6} {d:>10.4} {d:>9.1f}%\n", .{
f.name, f.total_bits, f.exp_bits, f.mant_bits, f.exp_mant_ratio, f.golden_pct,
});
}
try writer.print(" {s}\n\n", .{"-" * 72});
}

pub fn autoSelectFormat(layer_idx: usize, total_layers: usize) FormatInfo {
const ratio = @as(f64, @floatFromInt(layer_idx)) / @as(f64, @floatFromInt(total_layers));
if (ratio < 0.2) return FP16_INFO;
if (ratio < 0.8) return GF16_INFO;
return BF16_INFO;
}

test "phi distance GF16" {
const dist = phiDistance(6, 9);
try std.testing.expect(dist < 0.05);
try std.testing.expect(dist > 0);
}

test "phi distance GF16 is closest" {
const gf16_dist = phiDistance(6, 9);
const bf16_dist = phiDistance(8, 7);
const fp16_dist = phiDistance(5, 10);
try std.testing.expect(gf16_dist < bf16_dist);
try std.testing.expect(gf16_dist < fp16_dist);
}

test "golden pct GF16" {
const pct = goldenPct(6, 9);
try std.testing.expect(pct > 90.0);
}

test "auto select format" {
try std.testing.expectEqualStrings("FP16", autoSelectFormat(0, 10).name);
try std.testing.expectEqualStrings("GF16", autoSelectFormat(5, 10).name);
try std.testing.expectEqualStrings("BF16", autoSelectFormat(9, 10).name);
}

test "trinity identity" {
try std.testing.expectApproxEqAbs(@as(f64, 3.0), TRINITY, 1e-10);
}
64 changes: 64 additions & 0 deletions src/brain/fusiform_gyrus.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
const std = @import("std");

pub fn encodeF32ToGF16(v: f32) u16 {
if (v == 0.0) return 0;
if (!std.math.isFinite(v)) return if (v < 0) 0xFFFF else 0x7FFF;

const sign: u16 = if (v < 0) 1 << 15 else 0;
const abs_v = @abs(v);

var exp: i16 = 0;
var mant_f: f64 = abs_v;
while (mant_f >= 1.0 and exp < 31) : (exp += 1) mant_f /= 2.0;
while (mant_f < 0.5 and exp > -32) : (exp -= 1) mant_f *= 2.0;

const exp_u6: u16 = @intCast(std.math.clamp(@as(i16, 31) + exp, 0, 63));
const mant_u9: u16 = @intFromFloat(std.math.clamp((mant_f - 0.5) * 512.0, 0, 511));

return sign | (exp_u6 << 9) | (mant_u9 & 0x1FF);
}

pub fn decodeGF16ToF32(raw: u16) f32 {
if (raw == 0) return 0.0;
if (raw == 0x8000) return -0.0;

const sign: f32 = if ((raw >> 15) & 1 == 1) -1.0 else 1.0;
const exp: u16 = (raw >> 9) & 0x3F;
const mant: u16 = raw & 0x1FF;

if (exp == 0x3F) return if (sign < 0) -std.math.inf(f32) else std.math.inf(f32);

const exp_f: f32 = @floatFromInt(@as(i32, @intCast(exp)) - 31);
const mant_f: f32 = 0.5 + @as(f32, @floatFromInt(mant)) / 512.0;
return sign * mant_f * std.math.pow(f32, 2.0, exp_f);
}

pub fn encodeBF16(v: f32) u16 {
const bits: u32 = @bitCast(v);
return @intCast(bits >> 16);
}

pub fn decodeBF16(raw: u16) f32 {
const bits: u32 = @as(u32, raw) << 16;
return @bitCast(bits);
}

test "f32 to GF16 roundtrip" {
const values = [_]f32{ 0.5, 1.0, 2.0, 3.14, 100.0 };
for (values) |v| {
const encoded = encodeF32ToGF16(v);
const decoded = decodeGF16ToF32(encoded);
const err = @abs(v - decoded) / v;
try std.testing.expect(err < 0.01);
}
}

test "BF16 roundtrip" {
const values = [_]f32{ 0.5, 1.0, 2.0, 3.14 };
for (values) |v| {
const encoded = encodeBF16(v);
const decoded = decodeBF16(encoded);
const err = @abs(v - decoded) / v;
try std.testing.expect(err < 0.01);
}
}
82 changes: 82 additions & 0 deletions src/brain/orbitofrontal_value.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
const std = @import("std");

pub const PHI: f64 = 1.6180339887498948482;

pub const FormatDecision = enum {
gf16,
bf16,
fp16,
ternary,
};

pub const LayerAnalysis = struct {
layer_idx: usize,
weight_std: f64,
weight_range: f64,
recommended: FormatDecision,
confidence: f64,
};

pub fn recommendFormat(weight_std: f64, weight_range: f64) FormatDecision {
if (weight_std < 0.1) return .ternary;
if (weight_range < 2.0 and weight_std < 0.5) return .gf16;
if (weight_range > 100.0) return .bf16;
return .fp16;
}

pub fn analyzeLayer(weights: []const f64, layer_idx: usize) LayerAnalysis {
var sum: f64 = 0;
var sum_sq: f64 = 0;
var min_val: f64 = std.math.inf(f64);
var max_val: f64 = -std.math.inf(f64);

for (weights) |w| {
sum += w;
sum_sq += w * w;
if (w < min_val) min_val = w;
if (w > max_val) max_val = w;
}

const n: f64 = @floatFromInt(weights.len);
const mean = sum / n;
const variance = sum_sq / n - mean * mean;
const std_dev = @sqrt(@max(variance, 0));
const range = max_val - min_val;

const recommended = recommendFormat(std_dev, range);

var confidence: f64 = 0.5;
switch (recommended) {
.gf16 => confidence = 1.0 - @abs(std_dev - PHI_INV) / PHI_INV,
.ternary => confidence = 1.0 - std_dev,
.bf16 => confidence = @min(range / 1000.0, 0.95),
.fp16 => confidence = 0.7,
}

return .{
.layer_idx = layer_idx,
.weight_std = std_dev,
.weight_range = range,
.recommended = recommended,
.confidence = std.math.clamp(confidence, 0.0, 1.0),
};
}

test "recommend format for small weights" {
try std.testing.expectEqual(FormatDecision.ternary, recommendFormat(0.05, 0.3));
}

test "recommend format for medium weights" {
try std.testing.expectEqual(FormatDecision.gf16, recommendFormat(0.3, 1.5));
}

test "recommend format for large range" {
try std.testing.expectEqual(FormatDecision.bf16, recommendFormat(5.0, 500.0));
}

test "analyze layer" {
const weights = [_]f64{ 0.1, 0.2, -0.1, 0.3, -0.2, 0.05 };
const analysis = analyzeLayer(&weights, 0);
try std.testing.expect(analysis.weight_std > 0);
try std.testing.expect(analysis.weight_range > 0);
}
75 changes: 75 additions & 0 deletions src/brain/weber_tuning.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
const std = @import("std");

pub const PHI: f64 = 1.6180339887498948482;

pub const WeberLevel = enum(u8) {
fine = 0,
medium = 1,
coarse = 2,
};

pub fn weberQuantize(value: f64, jnd_fraction: f64) i2 {
if (@abs(value) < jnd_fraction * 0.5) return 0;
if (value > 0) return 1;
if (value < 0) return -1;
return 0;
}

pub fn weberQuantizeLevels(value: f64, levels: usize) i64 {
if (value == 0) return 0;
const sign: i64 = if (value > 0) 1 else -1;
const abs_v = @abs(value);
const log_val = std.math.log(f64, std.math.e, abs_v + 1.0);
const quantized = @round(log_val * @as(f64, @floatFromInt(levels)) / 5.0);
return sign * @as(i64, @intFromFloat(@min(@abs(quantized), @as(f64, @floatFromInt(levels)))));
}

pub fn adaptiveJND(base_jnd: f64, magnitude: f64) f64 {
return base_jnd * (1.0 + std.math.log1p(@abs(magnitude)));
}

pub fn ternaryEncode(values: []const f64, jnd: f64, output: []i2) void {
for (values, output) |v, *o| {
o.* = weberQuantize(v, jnd);
}
}

pub fn ternaryStats(encoded: []const i2) struct { pos: usize, neg: usize, zero: usize, sparsity: f64 } {
var pos: usize = 0;
var neg: usize = 0;
var zero: usize = 0;
for (encoded) |v| {
if (v > 0) pos += 1;
if (v < 0) neg += 1;
if (v == 0) zero += 1;
}
return .{
.pos = pos,
.neg = neg,
.zero = zero,
.sparsity = @as(f64, @floatFromInt(zero)) / @as(f64, @floatFromInt(encoded.len)),
};
}

test "weber quantize" {
try std.testing.expectEqual(@as(i2, 1), weberQuantize(0.5, 0.1));
try std.testing.expectEqual(@as(i2, -1), weberQuantize(-0.5, 0.1));
try std.testing.expectEqual(@as(i2, 0), weberQuantize(0.01, 0.1));
}

test "adaptive JND" {
const jnd_small = adaptiveJND(0.1, 0.1);
const jnd_large = adaptiveJND(0.1, 10.0);
try std.testing.expect(jnd_large > jnd_small);
}

test "ternary encode and stats" {
const values = [_]f64{ 0.5, -0.3, 0.01, 0.8, -0.02 };
var encoded: [5]i2 = undefined;
ternaryEncode(&values, 0.1, &encoded);

const stats = ternaryStats(&encoded);
try std.testing.expectEqual(@as(usize, 2), stats.pos);
try std.testing.expectEqual(@as(usize, 1), stats.neg);
try std.testing.expectEqual(@as(usize, 2), stats.zero);
}
2 changes: 1 addition & 1 deletion src/hslm/cli.zig
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const std = @import("std");

pub fn main() !u8 {
std.debug.print("HSLM CLI - Working\\n", .{});
std.debug.print("HSLM CLI - Working\n", .{});
return 0;
}
Loading