Skip to documentation
SLOP

tiny.pluck.wmc

Reference tiny.pluck wmc

Defined in tiny.pluck.

API (7)

Actions

Public operations.

Types and contracts

Public types and contracts.

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

Source

Called byCallsNo direct callstest sourcelib.pluck.src.wmctest: DeferredCaches separates deferr...wmc.DeferredCachesdeinit
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callstest sourcelib.pluck.src.wmctest: DeferredCaches separates deferr...wmc.DeferredCachesinit
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsevaluatorcompiletest sourcelib.pluck.src.wmctest: parallel WMC handles exact divi...test sourcelib.pluck.src.wmctest: parallel WMC produces same resu...wmccomputeWmcSequentialprivate sourcelib.pluck.src.wmcparallelWmcWorkerwmccomputeWmcParallel
Static calls · unresolved targets: 1 · external targets: 4.
Called byCallsNo direct callsevaluatorcompilewmccomputeWmcParalleltest sourcelib.pluck.src.wmctest: parallel WMC handles exact divi...test sourcelib.pluck.src.wmctest: parallel WMC produces same resu...wmccomputeWmcSequential
Static calls · unresolved targets: 0 · external targets: 4.

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

zig
pub const wmc = @import("wmc.zig");

Source: lib/pluck/src/wmc.zig

zig
const std = @import("std");const sys = @import("sys");const Allocator = std.mem.Allocator;const bdd = @import("bdd.zig");const Bdd = bdd.Bdd;const Manager = bdd.Manager;const WmcParams = bdd.WmcParams;const weight_dd = @import("weight.zig");const WeightDD = weight_dd.WeightDD;const Weight = weight_dd.Weight;const runtime = @import("runtime.zig");const RuntimeValue = runtime.RuntimeValue;pub const World = runtime.GuardedWorld;pub const WeightedResult = struct {    value: *RuntimeValue,    probability: f64,};pub const DeferredCaches = struct {    deferred: std.AutoHashMap(u64, f64),    weighted: std.AutoHashMap(u64, f64),    pub fn init(allocator: Allocator) DeferredCaches {        return .{            .deferred = std.AutoHashMap(u64, f64).init(allocator),            .weighted = std.AutoHashMap(u64, f64).init(allocator),        };    }    pub fn deinit(self: *DeferredCaches) void {        self.weighted.deinit();        self.deferred.deinit();    }};const ParallelWmcContext = struct {    cache_allocator: Allocator,    worlds: []const World,    weighted_results: []WeightedResult,    wmc_params: *const WmcParams,    weight_dd: *const WeightDD,    weight_root: Weight,};fn parallelWmcWorker(ctx: *const ParallelWmcContext, start: usize, end: usize) void {    var cache = std.AutoHashMap(u64, f64).init(ctx.cache_allocator);    defer cache.deinit();    for (start..end) |i| {        ctx.weighted_results[i] = WeightedResult{            .value = ctx.worlds[i].value,            .probability = weight_dd.wmcWeightedWithCache(                ctx.weight_dd,                ctx.worlds[i].guard,                ctx.weight_root,                ctx.wmc_params,                &cache,            ),        };    }}pub fn computeWmcParallel(    result_allocator: Allocator,    cache_allocator: Allocator,    worlds: []const World,    wmc_params: *const WmcParams,    weight_dd_ctx: *const WeightDD,    weight_root: Weight,    num_threads: ?usize,) ![]WeightedResult {    if (!sys.thread.threadsSupported()) {        return computeWmcSequential(result_allocator, worlds, wmc_params, weight_dd_ctx, weight_root);    } else {        if (worlds.len == 0) {            return try result_allocator.alloc(WeightedResult, 0);        }        const weighted_results = try result_allocator.alloc(WeightedResult, worlds.len);        errdefer result_allocator.free(weighted_results);        const worker_count = @max(1, num_threads orelse 1);        const ctx = ParallelWmcContext{            .cache_allocator = cache_allocator,            .worlds = worlds,            .weighted_results = weighted_results,            .wmc_params = wmc_params,            .weight_dd = weight_dd_ctx,            .weight_root = weight_root,        };        if (worker_count == 1 or worlds.len < 2) {            parallelWmcWorker(&ctx, 0, worlds.len);            return weighted_results;        }        const total_threads = @min(worker_count, worlds.len);        const worker_threads = total_threads - 1;        const threads = try result_allocator.alloc(sys.thread.JoinHandle, worker_threads);        defer result_allocator.free(threads);        var spawned_threads: usize = 0;        errdefer {            for (threads[0..spawned_threads]) |thread| {                thread.join();            }        }        var start: usize = 0;        const base_chunk_size = worlds.len / total_threads;        const remainder = worlds.len % total_threads;        for (threads, 0..) |*thread, i| {            const extra: usize = if (i < remainder) 1 else 0;            const chunk_size = base_chunk_size + extra;            const end = start + chunk_size;            thread.* = try sys.thread.spawn(parallelWmcWorker, .{ &ctx, start, end });            spawned_threads += 1;            start = end;        }        if (start < worlds.len) {            parallelWmcWorker(&ctx, start, worlds.len);        }        for (threads) |thread| {            thread.join();        }        return weighted_results;    }}pub fn computeWmcSequential(    allocator: Allocator,    worlds: []const World,    wmc_params: *const WmcParams,    weight_dd_ctx: *const WeightDD,    weight_root: Weight,) ![]WeightedResult {    var weighted_results = try allocator.alloc(WeightedResult, worlds.len);    errdefer allocator.free(weighted_results);    var cache = std.AutoHashMap(u64, f64).init(allocator);    defer cache.deinit();    for (worlds, 0..) |world, i| {        weighted_results[i] = WeightedResult{            .value = world.value,            .probability = weight_dd.wmcWeightedWithCache(weight_dd_ctx, world.guard, weight_root, wmc_params, &cache),        };    }    return weighted_results;}test "DeferredCaches separates deferred and weighted key spaces" {    var caches = DeferredCaches.init(std.testing.allocator);    defer caches.deinit();    const key: u64 = 42;    try caches.deferred.put(key, 1.25);    try caches.weighted.put(key, 2.5);    try std.testing.expectApproxEqAbs(@as(f64, 1.25), caches.deferred.get(key).?, 1e-12);    try std.testing.expectApproxEqAbs(@as(f64, 2.5), caches.weighted.get(key).?, 1e-12);}test "parallel WMC produces same results as sequential" {    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena.deinit();    const allocator = arena.allocator();    var manager = try Manager.init(allocator);    defer manager.deinit();    var weight_ctx = try WeightDD.init(allocator, &manager);    defer weight_ctx.deinit();    const weight_root = try weight_ctx.leaf(1.0);    const num_worlds = 32;    const worlds = try allocator.alloc(World, num_worlds);    var vars: [5]Bdd = undefined;    for (0..5) |i| {        vars[i] = try manager.newVar(true);    }    for (0..num_worlds) |i| {        const val = try RuntimeValue.initNative(allocator, .{ .int = @intCast(i) });        var guard = Bdd.TRUE;        for (0..5) |j| {            const use_var = (i >> @intCast(j)) & 1 == 1;            if (use_var) {                guard = try manager.bddAnd(guard, vars[j]);            }        }        worlds[i] = World{ .value = val, .guard = guard };    }    var wmc_params = WmcParams.init(allocator);    defer wmc_params.deinit();    for (0..manager.numVars()) |v| {        try wmc_params.setWeight(@intCast(v), 0.5, 0.5);    }    const seq_results = try computeWmcSequential(allocator, worlds, &wmc_params, &weight_ctx, weight_root);    defer allocator.free(seq_results);    const par_results = try computeWmcParallel(allocator, std.testing.allocator, worlds, &wmc_params, &weight_ctx, weight_root, 2);    defer allocator.free(par_results);    try std.testing.expectEqual(seq_results.len, par_results.len);    for (seq_results, par_results) |seq, par| {        try std.testing.expectEqual(seq.value, par.value);        try std.testing.expectApproxEqAbs(seq.probability, par.probability, 1e-15);    }}test "parallel WMC handles exact divisibility by thread count" {    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena.deinit();    const allocator = arena.allocator();    var manager = try Manager.init(allocator);    defer manager.deinit();    var weight_ctx = try WeightDD.init(allocator, &manager);    defer weight_ctx.deinit();    const weight_root = try weight_ctx.leaf(1.0);    const num_worlds = 9;    const worlds = try allocator.alloc(World, num_worlds);    var vars: [4]Bdd = undefined;    for (0..4) |i| {        vars[i] = try manager.newVar(true);    }    for (0..num_worlds) |i| {        const val = try RuntimeValue.initNative(allocator, .{ .int = @intCast(i) });        var guard = Bdd.TRUE;        for (0..4) |j| {            const use_var = (i >> @intCast(j)) & 1 == 1;            if (use_var) {                guard = try manager.bddAnd(guard, vars[j]);            }        }        worlds[i] = World{ .value = val, .guard = guard };    }    var wmc_params = WmcParams.init(allocator);    defer wmc_params.deinit();    for (0..manager.numVars()) |v| {        try wmc_params.setWeight(@intCast(v), 0.5, 0.5);    }    const seq_results = try computeWmcSequential(allocator, worlds, &wmc_params, &weight_ctx, weight_root);    defer allocator.free(seq_results);    const par_results = try computeWmcParallel(allocator, std.testing.allocator, worlds, &wmc_params, &weight_ctx, weight_root, 2);    defer allocator.free(par_results);    try std.testing.expectEqual(seq_results.len, par_results.len);    for (seq_results, par_results, 0..) |seq, par, i| {        try std.testing.expectEqual(seq.value, par.value);        try std.testing.expectApproxEqAbs(seq.probability, par.probability, 1e-15);        try std.testing.expect(par.probability >= 0 and par.probability <= 1);        _ = i;    }}

Audit

Definitions7
Public names10
Members4
Version26.7.0
Revisiondaab053ee433