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
31 changes: 31 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: CI

# This repository has never had a workflow that builds it.
#
# That is the same gap that hid sixteen defects in gHashTag/zig-golden-float and
# five in gHashTag/zig-hdc: a package can look maintained, be imported by name,
# and not compile for anybody, because nothing ever asked it to.
#
# Pinned to 0.15.2 because that is the version the packages in this estate that
# would consume it are built with. Building on something else would prove the
# package works for somebody who is not the consumer.

on:
push:
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with:
version: 0.15.2
- run: zig build
- run: zig build test
83 changes: 48 additions & 35 deletions build.zig
Original file line number Diff line number Diff line change
@@ -1,45 +1,58 @@
// zig-half build script
//
// The previous version of this file had never compiled and could not have. It
// declared `pub fn test(b: *std.Build)`, and `test` is a keyword; it assigned
// `b.standardTargetOptions` without calling it; it passed two arguments to
// installArtifact and read `b.step` as a field. None of that is a version
// difference -- it is a sketch shaped like a build script, and nothing in this
// repository ever ran it, because there was no workflow that built anything.
//
// Rewritten for 0.15, the version the packages that would consume this are
// built with.
const std = @import("std");

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

const lib = b.addStaticLibrary(.{
.name = "zig-half",
.root_source_file = "src/root.zig",
const root = b.addModule("zig-half", .{
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
});
_ = root;

b.installArtifact(lib, .{});
}

pub fn test(b: *std.Build) !void {
const test_step = b.addTest(.{
.root_source_file = "src/f16_utils.zig",
.name = "f16_utils_tests",
});

_ = b.addTest(.{
.root_source_file = "src/f16_shadow.zig",
.name = "f16_shadow_tests",
});

_ = b.addTest(.{
.root_source_file = "src/sparse_simd.zig",
.name = "sparse_simd_tests",
});

_ = b.addTest(.{
.root_source_file = "src/ternary_pack.zig",
.name = "ternary_pack_tests",
});

_ = b.addTest(.{
.root_source_file = "src/simd_config.zig",
.name = "simd_config_tests",
const lib = b.addLibrary(.{
.name = "zig-half",
.linkage = .static,
.root_module = b.createModule(.{
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
}),
});

b.step.dependOn(&test_step.step);
b.installArtifact(lib);

// One test target per file, as before, plus the module root. The root was
// not tested at all previously, which is the surface every consumer gets:
// Zig analyses top-level declarations lazily, so a test run over the other
// files proves nothing about the declarations they do not reference.
const test_step = b.step("test", "Run the tests");
for ([_][]const u8{
"src/root.zig",
"src/f16_utils.zig",
"src/f16_shadow.zig",
"src/sparse_simd.zig",
"src/ternary_pack.zig",
"src/simd_config.zig",
}) |path| {
const t = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path(path),
.target = target,
.optimize = optimize,
}),
});
test_step.dependOn(&b.addRunArtifact(t).step);
}
}
7 changes: 5 additions & 2 deletions build.zig.zon
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
.{
.name = "zig-half",
.name = .zig_half,
.version = "0.1.0",
.paths = .{"src"},
.minimum_zig_version = "0.15.0",
.fingerprint = 0x3330a2c2540783d1,
.paths = .{ "src", "build.zig", "build.zig.zon" },
.dependencies = .{},
}
2 changes: 1 addition & 1 deletion src/f16_utils.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// φ² + 1/φ² = 3 | TRINITY

const std = @import("std");
const simd_config = @import("src/simd_config.zig");
const simd_config = @import("simd_config.zig");

// ═══════════════════════════════════════════════════════════════════════════════
// ADAPTIVE VECTOR TYPES — Width from CPU feature detection
Expand Down
139 changes: 70 additions & 69 deletions src/root.zig
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// zig-half — f16/bf16 SIMD library for Zig
//
// A high-performance half-precision float library with:
// - Adaptive SIMD width (AVX2, AVX-512, NEON, SSE2)
// - f16 ↔ f32 conversions with zero-copy vectorization
// - Ternary quantization {-1, 0, +1} with 2-bit packing
// - Sparse ternary matvec with zero-chunk skipping
// - Shadow weight storage for gradient accumulation
// - Comprehensive benchmarks
// The re-exports below were written as `pub use module.{ A, B as C };`, which is
// Rust. Zig has no `use` statement and no `as` aliasing, so this file -- the
// module root, the surface every consumer imports -- has never been valid Zig,
// and the package has therefore never been usable by anybody. Nothing reported
// it because the repository had no workflow that built anything.
//
// Each of those blocks is now the Zig it was standing in for: one `pub const`
// per name, with the aliases preserved exactly as they were spelled.
//
// Extracted from Trinity HSLM training infrastructure.
// See: https://github.com/gHashTag/trinity
Expand All @@ -15,80 +16,72 @@ const std = @import("std");

// Re-export SIMD configuration and detection
pub const simd_config = @import("simd_config.zig");
pub use simd_config.{ capabilities, VecF16, VecF32, VecI8, zeroVecF16, zeroVecF32, zeroVecI8 };
pub const capabilities = simd_config.capabilities;
pub const VecF16 = simd_config.VecF16;
pub const VecF32 = simd_config.VecF32;
pub const VecI8 = simd_config.VecI8;
pub const zeroVecF16 = simd_config.zeroVecF16;
pub const zeroVecF32 = simd_config.zeroVecF32;
pub const zeroVecI8 = simd_config.zeroVecI8;

// Re-export f16 utilities
pub const f16_utils = @import("f16_utils.zig");
pub use f16_utils.{
VEC_F16_SIZE,
VEC_F32_SIZE,
VecF16 as VecF16Alias,
VecF32 as VecF32Alias,
zeroVecF16 as zeroVecF16Alias,
zeroVecF32 as zeroVecF32Alias,
f32ToF16Slice,
f16ToF32Slice,
vecF16ToF32,
vecF32ToF16,
isTernarySafeF16,
countTernarySafeF16,
countNonFiniteF16,
maxAbsF16,
maxAbsF16Simd,
dotProductF16,
l2NormF16,
cosineSimilarityF16,
quantizeF16ToTernary,
};
pub const VEC_F16_SIZE = f16_utils.VEC_F16_SIZE;
pub const VecF16Alias = f16_utils.VecF16;
pub const VecF32Alias = f16_utils.VecF32;
pub const zeroVecF16Alias = f16_utils.zeroVecF16;
pub const zeroVecF32Alias = f16_utils.zeroVecF32;
pub const f32ToF16Slice = f16_utils.f32ToF16Slice;
pub const f16ToF32Slice = f16_utils.f16ToF32Slice;
pub const vecF16ToF32 = f16_utils.vecF16ToF32;
pub const vecF32ToF16 = f16_utils.vecF32ToF16;
pub const isTernarySafeF16 = f16_utils.isTernarySafeF16;
pub const countTernarySafeF16 = f16_utils.countTernarySafeF16;
pub const countNonFiniteF16 = f16_utils.countNonFiniteF16;
pub const maxAbsF16 = f16_utils.maxAbsF16;
pub const maxAbsF16Simd = f16_utils.maxAbsF16Simd;
pub const dotProductF16 = f16_utils.dotProductF16;
pub const l2NormF16 = f16_utils.l2NormF16;
pub const cosineSimilarityF16 = f16_utils.cosineSimilarityF16;
pub const quantizeF16ToTernary = f16_utils.quantizeF16ToTernary;

// Re-export f16 shadow weights
pub const f16_shadow = @import("f16_shadow.zig");
pub use f16_shadow.{
F16ShadowStorage,
DEFAULT_SYNC_INTERVAL,
DEFAULT_QUANTIZE_THRESHOLD,
f32ToF16Slice as f32ToF16SliceShadow,
f16ToF32Slice as f16ToF32SliceShadow,
dotProductF16 as dotProductF16Shadow,
};
pub const F16ShadowStorage = f16_shadow.F16ShadowStorage;
pub const f32ToF16SliceShadow = f16_shadow.f32ToF16Slice;
pub const f16ToF32SliceShadow = f16_shadow.f16ToF32Slice;
pub const dotProductF16Shadow = f16_shadow.dotProductF16;

// Re-export sparse SIMD
pub const sparse_simd = @import("sparse_simd.zig");
pub use sparse_simd.{
VEC_I8_SIZE,
VEC_F16_SIZE as VEC_F16_SIZE_Sparse,
VEC_F32_SIZE as VEC_F32_SIZE_Sparse,
VecI8 as VecI8Alias,
VecF16 as VecF16SparseAlias,
VecF32 as VecF32SparseAlias,
zeroVecI8 as zeroVecI8Alias,
zeroVecF16 as zeroVecF16SparseAlias,
sparseTernaryDot,
denseTernaryDot,
sparseTernaryMatvec,
denseTernaryMatvec,
countZeroChunks,
sparsityRatio,
estimateSpeedup,
};
pub const VEC_I8_SIZE = sparse_simd.VEC_I8_SIZE;
pub const VEC_F16_SIZE_Sparse = sparse_simd.VEC_F16_SIZE;
pub const VEC_F32_SIZE_Sparse = sparse_simd.VEC_F32_SIZE;
pub const VecI8Alias = sparse_simd.VecI8;
pub const VecF16SparseAlias = sparse_simd.VecF16;
pub const VecF32SparseAlias = sparse_simd.VecF32;
pub const zeroVecI8Alias = sparse_simd.zeroVecI8;
pub const zeroVecF16SparseAlias = sparse_simd.zeroVecF16;
pub const sparseTernaryDot = sparse_simd.sparseTernaryDot;
pub const denseTernaryDot = sparse_simd.denseTernaryDot;
pub const sparseTernaryMatvec = sparse_simd.sparseTernaryMatvec;
pub const denseTernaryMatvec = sparse_simd.denseTernaryMatvec;
pub const countZeroChunks = sparse_simd.countZeroChunks;
pub const sparsityRatio = sparse_simd.sparsityRatio;
pub const estimateSpeedup = sparse_simd.estimateSpeedup;

// Re-export ternary packing
pub const ternary_pack = @import("ternary_pack.zig");
pub use ternary_pack.{
TRIT_NEG,
TRIT_ZERO,
TRIT_POS,
packTernary16,
unpackTernary16,
packTernarySlice,
unpackTernarySlice,
tritToChar,
charToTrit,
tritsToString,
stringToTrits,
countTrits,
compressionRatio,
};
pub const packTernary16 = ternary_pack.packTernary16;
pub const unpackTernary16 = ternary_pack.unpackTernary16;
pub const packTernarySlice = ternary_pack.packTernarySlice;
pub const unpackTernarySlice = ternary_pack.unpackTernarySlice;
pub const tritToChar = ternary_pack.tritToChar;
pub const charToTrit = ternary_pack.charToTrit;
pub const tritsToString = ternary_pack.tritsToString;
pub const stringToTrits = ternary_pack.stringToTrits;
pub const countTrits = ternary_pack.countTrits;
pub const compressionRatio = ternary_pack.compressionRatio;

// ═════════════════════════════════════════════════════════════════════════════
// VERSION & INFO
Expand Down Expand Up @@ -142,3 +135,11 @@ pub inline fn printConfig() void {
// // Print SIMD info
// zig_half.printConfig();
// }

test "every public declaration of this module is analysed" {
// src/root.zig is what a consumer imports, and no test target rooted it
// before -- so the one surface that matters was the one never compiled.
// The same omission hid sixteen defects in gHashTag/zig-golden-float and
// five in gHashTag/zig-hdc.
@import("std").testing.refAllDeclsRecursive(@This());
}
2 changes: 1 addition & 1 deletion src/simd_bench.zig
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
const std = @import("std");
const f16_utils = @import("f16_utils.zig");
const sparse_simd = @import("sparse_simd.zig");
const simd_config = @import("src/simd_config.zig");
const simd_config = @import("simd_config.zig");

const EMBED_DIM = 243;
const HIDDEN_DIM = 729;
Expand Down
6 changes: 5 additions & 1 deletion src/simd_config.zig
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,11 @@ pub fn simdInfoString() []const u8 {
/// Print SIMD configuration at runtime
/// Note: Only works in executables, not in test mode
pub fn printSimdConfig() void {
const stdout = std.io.getStdOut().writer();
// std.io.getStdOut() was removed in 0.15.
var stdout_buffer: [4096]u8 = undefined;
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
const stdout = &stdout_writer.interface;
defer stdout.flush() catch {};

stdout.print("SIMD Configuration:\n", .{}) catch return;
stdout.print(" Architecture: {s}\n", .{capabilities.arch_name}) catch return;
Expand Down
2 changes: 1 addition & 1 deletion src/sparse_simd.zig
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// φ² + 1/φ² = 3 | TRINITY

const std = @import("std");
const simd_config = @import("src/simd_config.zig");
const simd_config = @import("simd_config.zig");

// ═══════════════════════════════════════════════════════════════════════════════
// ADAPTIVE VECTOR TYPES
Expand Down
Loading