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
32 changes: 32 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# This repository had no build.zig and no workflow. Three source files, fifteen
# test blocks, and a manifest that declared a dependency by URL with no hash —
# so nothing could fetch it, nothing could build it, and nobody could depend on
# it. The four imports in knowledge_graph.zig pointed at sibling files that live
# in gHashTag/zig-golden-float, whose own packed_vsa.zig imported
# "knowledge_graph.zig" right back. Neither half compiled.
name: build

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with:
# The version this package targets. Local 0.16 reports failures that
# do not exist here (std.io.getStdOut, ArrayList.init, std.fs) and
# would hide at least one that does.
version: 0.15.2

- name: zig build
run: zig build

- name: zig build test
run: zig build test --summary all
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ zig-out/

.env*
!.env.example
.zig-cache/
zig-out/
zig-pkg/
48 changes: 48 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const std = @import("std");

// There was no build.zig in this repository at all. Three source files, fifteen
// test blocks, a manifest declaring a dependency without a hash — and nothing
// that could compile any of it.
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});

const golden = b.dependency("zig_golden_float", .{
.target = target,
.optimize = optimize,
}).module("golden-float");

const kg_mod = b.addModule("zig-knowledge-graph", .{
.root_source_file = b.path("src/knowledge_graph.zig"),
.target = target,
.optimize = optimize,
});
kg_mod.addImport("zig_golden_float", golden);

// kg_cli and kg_server are NOT built. Both were written against Zig 0.14
// and never migrated: std.io.getStdOut is gone, std.ArrayList is unmanaged
// so .init(allocator) and one-argument .append no longer exist, and
// http.Server.init takes a reader rather than a connection. That is a
// migration across roughly 1300 lines with many call sites, and it is
// tracked separately.
//
// The library is the part other packages depend on, and it is what this
// change makes usable. Building the two binaries would keep the whole
// package unbuildable for the sake of two tools that have never run.

// Each root gets its own test target. A single root would reach only what it
// references, and under Zig's lazy analysis an unreferenced import is not a
// weakly-checked file — it is an absent one, along with its test blocks.
const test_step = b.step("test", "Run tests");
inline for (.{
.{ "knowledge_graph", "src/knowledge_graph.zig" },
}) |t| {
const tm = b.createModule(.{
.root_source_file = b.path(t[1]),
.target = target,
.optimize = optimize,
});
tm.addImport("zig_golden_float", golden);
test_step.dependOn(&b.addRunArtifact(b.addTest(.{ .name = t[0], .root_module = tm })).step);
}
}
21 changes: 14 additions & 7 deletions build.zig.zon
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
{
.name = zig_knowledge_graph,
.version = "0.1.0",
.dependencies = .{
.zig_golden_float = .{
.url = "https://github.com/gHashTag/zig-golden-float/archive/main.tar.gz",
.{
// Was: a dependency declared by URL with no .hash, and no .fingerprint at
// all — so nothing could fetch it and nothing could depend on this package.
// There was also no build.zig, so there was nothing to run either.
.name = .zig_knowledge_graph,
.version = "0.1.0",
.fingerprint = 0x2a92e04f54905954,
.minimum_zig_version = "0.15.0",
.dependencies = .{
.zig_golden_float = .{
.url = "https://github.com/gHashTag/zig-golden-float/archive/e7ce32885de2a8c50b7b6a3030d0592202145dd1.tar.gz",
.hash = "golden_float-2.1.0-h7LKhUUNCwAtKVHQ56wjridCZVwXY7_oxT2hXD9xCDdF",
},
},
},
.paths = .{ "build.zig", "build.zig.zon", "src", "README.md", "LICENSE" },
}
73 changes: 45 additions & 28 deletions src/knowledge_graph.zig
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,17 @@
// φ² + 1/φ² = 3

const std = @import("std");
const vsa = @import("vsa.zig");
const hybrid = @import("hybrid.zig");
const packed_vsa = @import("packed_vsa.zig");
const packed_trit = @import("packed_trit.zig");
// These four were flat relative imports of files that are not in this
// repository. They are in gHashTag/zig-golden-float, whose own
// src/vsa/packed_vsa.zig imported "knowledge_graph.zig" — a file that is not
// in THAT repository, but is right here. One directory was split into two and
// every relative import was left pointing at the sibling that stayed behind,
// so neither half compiled. Pointed at the dependency instead.
const golden = @import("zig_golden_float");
const vsa = golden.vsa;
const hybrid = golden.bigint;
const packed_vsa = golden.packed_vsa;
const packed_trit = golden.packed_trit;

const HybridBigInt = hybrid.HybridBigInt;
const PackedBigInt = packed_trit.PackedBigInt;
Expand Down Expand Up @@ -364,7 +371,11 @@ pub const KnowledgeGraph = struct {
const file = try std.fs.cwd().createFile(path, .{});
defer file.close();

var writer = file.writer();
// Since 0.15 File.writer takes a buffer and returns a File.Writer;
// the thing with writeAll/writeInt on it is its .interface.
var write_buf: [4096]u8 = undefined;
var file_writer = file.writer(&write_buf);
const writer = &file_writer.interface;

// Header
try writer.writeAll(&FILE_MAGIC);
Expand Down Expand Up @@ -422,50 +433,56 @@ pub const KnowledgeGraph = struct {
try writer.writeInt(u32, graph_trit_len, .little);
const graph_packed_len = (self.graph_vector.trit_len + 4) / 5;
try writer.writeAll(self.graph_vector.data[0..graph_packed_len]);

// The writer is buffered now. Without this the tail of the graph never
// reaches disk and load() fails on a file that save() reported writing.
try file_writer.interface.flush();
}

/// and and file
pub fn load(path: []const u8, name_buffer: []u8) !Self {
const file = try std.fs.cwd().openFile(path, .{});
defer file.close();

var reader = file.reader();
var read_buf: [4096]u8 = undefined;
var file_reader = file.reader(&read_buf);
const reader = &file_reader.interface;
var result = Self.init();

// Header
var magic: [4]u8 = undefined;
_ = try reader.readAll(&magic);
try reader.readSliceAll(&magic);
if (!std.mem.eql(u8, &magic, &FILE_MAGIC)) {
return error.InvalidFileFormat;
}

const version = try reader.readInt(u32, .little);
const version = try reader.takeInt(u32, .little);
if (version != FILE_VERSION) {
return error.UnsupportedVersion;
}

const entity_count = try reader.readInt(u32, .little);
const relation_count = try reader.readInt(u32, .little);
const entity_count = try reader.takeInt(u32, .little);
const relation_count = try reader.takeInt(u32, .little);

// withby buffer for and
var name_offset: usize = 0;

// Entities
for (0..entity_count) |i| {
const name_len = try reader.readInt(u16, .little);
const name_len = try reader.takeInt(u16, .little);

// and and in buffer
const name_start = name_offset;
_ = try reader.readAll(name_buffer[name_offset .. name_offset + name_len]);
try reader.readSliceAll(name_buffer[name_offset .. name_offset + name_len]);
name_offset += name_len;

const id = try reader.readInt(u32, .little);
const trit_len = try reader.readInt(u32, .little);
const id = try reader.takeInt(u32, .little);
const trit_len = try reader.takeInt(u32, .little);
const packed_len = (trit_len + 4) / 5;

var vec = PackedBigInt.zero();
vec.trit_len = trit_len;
_ = try reader.readAll(vec.data[0..packed_len]);
try reader.readSliceAll(vec.data[0..packed_len]);

result.entities[i] = Entity{
.name = name_buffer[name_start .. name_start + name_len],
Expand All @@ -477,19 +494,19 @@ pub const KnowledgeGraph = struct {

// Relations
for (0..relation_count) |i| {
const name_len = try reader.readInt(u16, .little);
const name_len = try reader.takeInt(u16, .little);

const name_start = name_offset;
_ = try reader.readAll(name_buffer[name_offset .. name_offset + name_len]);
try reader.readSliceAll(name_buffer[name_offset .. name_offset + name_len]);
name_offset += name_len;

const id = try reader.readInt(u32, .little);
const trit_len = try reader.readInt(u32, .little);
const id = try reader.takeInt(u32, .little);
const trit_len = try reader.takeInt(u32, .little);
const packed_len = (trit_len + 4) / 5;

var vec = PackedBigInt.zero();
vec.trit_len = trit_len;
_ = try reader.readAll(vec.data[0..packed_len]);
try reader.readSliceAll(vec.data[0..packed_len]);

result.relations[i] = Relation{
.name = name_buffer[name_start .. name_start + name_len],
Expand All @@ -500,17 +517,17 @@ pub const KnowledgeGraph = struct {
}

// Triples
const triple_count = try reader.readInt(u32, .little);
const triple_count = try reader.takeInt(u32, .little);
for (0..triple_count) |i| {
const subject_id = try reader.readInt(u32, .little);
const predicate_id = try reader.readInt(u32, .little);
const object_id = try reader.readInt(u32, .little);
const trit_len = try reader.readInt(u32, .little);
const subject_id = try reader.takeInt(u32, .little);
const predicate_id = try reader.takeInt(u32, .little);
const object_id = try reader.takeInt(u32, .little);
const trit_len = try reader.takeInt(u32, .little);
const packed_len = (trit_len + 4) / 5;

var vec = PackedBigInt.zero();
vec.trit_len = trit_len;
_ = try reader.readAll(vec.data[0..packed_len]);
try reader.readSliceAll(vec.data[0..packed_len]);

result.triples[i] = Triple{
.subject_id = subject_id,
Expand All @@ -522,10 +539,10 @@ pub const KnowledgeGraph = struct {
}

// Graph vector
const graph_trit_len = try reader.readInt(u32, .little);
const graph_trit_len = try reader.takeInt(u32, .little);
const graph_packed_len = (graph_trit_len + 4) / 5;
result.graph_vector.trit_len = graph_trit_len;
_ = try reader.readAll(result.graph_vector.data[0..graph_packed_len]);
try reader.readSliceAll(result.graph_vector.data[0..graph_packed_len]);

return result;
}
Expand Down
Loading