Skip to documentation
SLOP

tiny.pluck.definition_order

Reference tiny.pluck definition_order

Defined in tiny.pluck.

API (6)

Actions

Public operations.

Types and contracts

Public types and contracts.

No direct callersNo direct callstiny.pluckdefinition order
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallstest sourcelib.pluck.src.ordertest: definition order min-fill choos...test sourcelib.pluck.src.ordertest: definition order topological re...private sourcelib.pluck.src.toplevel.queryinitExactSamplesQueryStateprivate sourcelib.pluck.src.toplevel.queryinitLpsmcQueryStatetoplevel.queryprocessMarginalQueryInternal+2 moreprivate sourcelib.pluck.src.ordercollectUserDefNamesSortedprivate sourcelib.pluck.src.orderminFillOrderDefsprivate sourcelib.pluck.src.ordertopologicalSortDefsdefinition_orderbuildDefinitionOrder
Static calls · unresolved targets: 1 · external targets: 2.

Source: lib/pluck/src/order.zig

zig
const std = @import("std");const pexpr = @import("pexpr.zig");const Allocator = std.mem.Allocator;const PExpr = pexpr.PExpr;const Definitions = pexpr.Definitions;const Symbol = pexpr.Symbol;pub const DefinitionOrderMode = enum {    none,    topological,    min_fill,};pub const DefinitionOrder = struct {    map: std.StringHashMapUnmanaged(i32) = .{},    pub fn getIndex(self: *const DefinitionOrder, name: Symbol) ?i32 {        return self.map.get(name);    }    pub fn deinit(self: *DefinitionOrder, allocator: Allocator) void {        self.map.deinit(allocator);    }};pub fn modeToString(mode: DefinitionOrderMode) []const u8 {    return switch (mode) {        .none => "none",        .topological => "topological",        .min_fill => "min-fill",    };}pub fn buildDefinitionOrder(    allocator: Allocator,    definitions: *const Definitions,    mode: DefinitionOrderMode,) !?*DefinitionOrder {    if (mode == .none) return null;    const def_names = try collectUserDefNamesSorted(allocator, definitions);    defer allocator.free(def_names);    if (def_names.len == 0) return null;    const ordered = switch (mode) {        .topological => try topologicalSortDefs(allocator, definitions, def_names),        .min_fill => try minFillOrderDefs(allocator, definitions, def_names),        .none => unreachable,    };    defer allocator.free(ordered);    const order = try allocator.create(DefinitionOrder);    order.* = DefinitionOrder{};    for (ordered, 0..) |name, idx| {        try order.map.put(allocator, name, @intCast(idx));    }    return order;}const UserDefinitionNameOrder = struct {    fn lessThan(_: void, a: Symbol, b: Symbol) bool {        return std.mem.lessThan(u8, a, b);    }};fn collectUserDefNamesSorted(allocator: Allocator, definitions: *const Definitions) ![]Symbol {    var names: std.ArrayList(Symbol) = .empty;    defer names.deinit(allocator);    var iter = definitions.defs.iterator();    while (iter.next()) |entry| {        if (entry.value_ptr.is_stdlib) continue;        try names.append(allocator, entry.value_ptr.name);    }    const slice = try names.toOwnedSlice(allocator);    std.sort.heap(Symbol, slice, {}, UserDefinitionNameOrder.lessThan);    return slice;}fn topologicalSortDefs(    allocator: Allocator,    definitions: *const Definitions,    def_names: []const Symbol,) ![]Symbol {    const n = def_names.len;    if (n == 0) return &[_]Symbol{};    var edges = try allocator.alloc(std.ArrayList(usize), n);    defer {        for (edges) |*e| e.deinit(allocator);        allocator.free(edges);    }    for (edges) |*e| e.* = .empty;    var name_to_idx = std.StringHashMap(usize).init(allocator);    defer name_to_idx.deinit();    for (def_names, 0..) |name, i| {        try name_to_idx.put(name, i);    }    for (def_names, 0..) |name, i| {        const def = definitions.defs.get(name) orelse continue;        var deps: std.ArrayList(usize) = .empty;        defer deps.deinit(allocator);        collectDefinedRefs(def.expr, &name_to_idx, &deps, allocator);        for (deps.items) |dep_idx| {            try edges[dep_idx].append(allocator, i);        }    }    var in_degree = try allocator.alloc(usize, n);    defer allocator.free(in_degree);    @memset(in_degree, 0);    for (edges) |e| {        for (e.items) |dep_idx| {            in_degree[dep_idx] += 1;        }    }    var queue: std.ArrayList(usize) = .empty;    defer queue.deinit(allocator);    for (in_degree, 0..) |deg, i| {        if (deg == 0) try queue.append(allocator, i);    }    var result = try allocator.alloc(Symbol, n);    var result_idx: usize = 0;    while (queue.items.len > 0) {        const idx = queue.orderedRemove(0);        result[result_idx] = def_names[idx];        result_idx += 1;        for (edges[idx].items) |dep_idx| {            in_degree[dep_idx] -= 1;            if (in_degree[dep_idx] == 0) {                try queue.append(allocator, dep_idx);            }        }    }    if (result_idx < n) {        @memcpy(result, def_names);    }    return result;}fn minFillOrderDefs(    allocator: Allocator,    definitions: *const Definitions,    def_names: []const Symbol,) ![]Symbol {    const n = def_names.len;    if (n == 0) return &[_]Symbol{};    const adj_size = std.math.mul(usize, n, n) catch return error.OutOfMemory;    var adj = try allocator.alloc(u8, adj_size);    defer allocator.free(adj);    @memset(adj, 0);    var name_to_idx = std.StringHashMap(usize).init(allocator);    defer name_to_idx.deinit();    for (def_names, 0..) |name, i| {        try name_to_idx.put(name, i);    }    for (def_names, 0..) |name, i| {        const def = definitions.defs.get(name) orelse continue;        var deps: std.ArrayList(usize) = .empty;        defer deps.deinit(allocator);        collectDefinedRefs(def.expr, &name_to_idx, &deps, allocator);        for (deps.items) |dep_idx| {            adj[i * n + dep_idx] = 1;            adj[dep_idx * n + i] = 1;        }        for (deps.items, 0..) |dep_i, idx_i| {            for (deps.items[idx_i + 1 ..]) |dep_j| {                adj[dep_i * n + dep_j] = 1;                adj[dep_j * n + dep_i] = 1;            }        }    }    var eliminated = try allocator.alloc(bool, n);    defer allocator.free(eliminated);    @memset(eliminated, false);    var neighbors_buf = try allocator.alloc(usize, n);    defer allocator.free(neighbors_buf);    var order = try allocator.alloc(Symbol, n);    var out_idx: usize = 0;    while (out_idx < n) : (out_idx += 1) {        var best_var: ?usize = null;        var best_fill: usize = std.math.maxInt(usize);        var best_degree: usize = std.math.maxInt(usize);        for (0..n) |v| {            if (eliminated[v]) continue;            var degree: usize = 0;            for (0..n) |u| {                if (u == v or eliminated[u]) continue;                if (adj[v * n + u] != 0) {                    neighbors_buf[degree] = u;                    degree += 1;                }            }            var fill: usize = 0;            for (neighbors_buf[0..degree], 0..) |u, idx_i| {                for (neighbors_buf[idx_i + 1 .. degree]) |w| {                    if (adj[u * n + w] == 0) fill += 1;                }            }            const better = fill < best_fill or (fill == best_fill and (degree < best_degree or (degree == best_degree and (best_var == null or v < best_var.?))));            if (better) {                best_var = v;                best_fill = fill;                best_degree = degree;            }        }        const chosen = best_var orelse break;        var degree: usize = 0;        for (0..n) |u| {            if (u == chosen or eliminated[u]) continue;            if (adj[chosen * n + u] != 0) {                neighbors_buf[degree] = u;                degree += 1;            }        }        for (neighbors_buf[0..degree], 0..) |u, idx_i| {            for (neighbors_buf[idx_i + 1 .. degree]) |w| {                adj[u * n + w] = 1;                adj[w * n + u] = 1;            }        }        for (neighbors_buf[0..degree]) |u| {            adj[chosen * n + u] = 0;            adj[u * n + chosen] = 0;        }        eliminated[chosen] = true;        order[out_idx] = def_names[chosen];    }    return order;}fn collectDefinedRefs(    expr: *PExpr,    name_to_idx: *const std.StringHashMap(usize),    deps: *std.ArrayList(usize),    allocator: Allocator,) void {    switch (expr.head) {        .defined => |d| {            if (name_to_idx.get(d.name)) |idx| {                for (deps.items) |existing| {                    if (existing == idx) return;                }                deps.append(allocator, idx) catch {};            }        },        else => {},    }    for (expr.args) |arg| {        collectDefinedRefs(arg, name_to_idx, deps, allocator);    }}test "definition order topological respects dependencies" {    const allocator = std.testing.allocator;    var defs = Definitions.init(allocator);    defer defs.deinit();    const expr_b = try PExpr.initWithArgs(allocator, .{ .flip = {} }, &[_]*PExpr{        try PExpr.initWithArgs(allocator, .{ .const_native = .{ .float = 0.5 } }, &[_]*PExpr{}),    });    try defs.define("b", expr_b);    const expr_a = try PExpr.initWithArgs(allocator, .{ .defined = .{ .name = "b" } }, &[_]*PExpr{});    try defs.define("a", expr_a);    const order = (try buildDefinitionOrder(allocator, &defs, .topological)).?;    defer {        order.deinit(allocator);        allocator.destroy(order);    }    const idx_b = order.getIndex("b").?;    const idx_a = order.getIndex("a").?;    try std.testing.expect(idx_b < idx_a);}test "definition order min-fill chooses low-fill variable first" {    const allocator = std.testing.allocator;    var defs = Definitions.init(allocator);    defer defs.deinit();    const expr_d = try PExpr.initWithArgs(allocator, .{ .flip = {} }, &[_]*PExpr{        try PExpr.initWithArgs(allocator, .{ .const_native = .{ .float = 0.4 } }, &[_]*PExpr{}),    });    try defs.define("d", expr_d);    const expr_b = try PExpr.initWithArgs(allocator, .{ .defined = .{ .name = "d" } }, &[_]*PExpr{});    try defs.define("b", expr_b);    const expr_c = try PExpr.initWithArgs(allocator, .{ .defined = .{ .name = "d" } }, &[_]*PExpr{});    try defs.define("c", expr_c);    const expr_a = try PExpr.initWithArgs(allocator, .{ .app = {} }, &[_]*PExpr{        try PExpr.initWithArgs(allocator, .{ .defined = .{ .name = "b" } }, &[_]*PExpr{}),        try PExpr.initWithArgs(allocator, .{ .defined = .{ .name = "c" } }, &[_]*PExpr{}),    });    try defs.define("a", expr_a);    const order = (try buildDefinitionOrder(allocator, &defs, .min_fill)).?;    defer {        order.deinit(allocator);        allocator.destroy(order);    }    const idx_a = order.getIndex("a").?;    try std.testing.expectEqual(@as(i32, 0), idx_a);}

Source: lib/pluck/src/root.zig:10

zig
pub const definition_order = @import("order.zig");

Complete caller list for definition_order.buildDefinitionOrder

7 direct callers.

Audit

Definitions7
Public names7
Members4
Version26.7.0
Revisiondaab053ee433