From 7560ee91518ca7e47762308fec47bcf0c062f139 Mon Sep 17 00:00:00 2001 From: Peter Harpending Date: Sat, 11 Oct 2025 06:39:04 -0600 Subject: [PATCH] hacky as fuck truth table <-> sentence-fun logic works --- src/wfc.erl | 4 ++ src/wfc_bm.erl | 22 +++++-- src/wfc_sftt.erl | 149 +++++++++++++++++++++++++++++++++++++++++++++++ src/wfc_tts.erl | 4 +- 4 files changed, 173 insertions(+), 6 deletions(-) create mode 100644 src/wfc_sftt.erl diff --git a/src/wfc.erl b/src/wfc.erl index 27997c6..79331d2 100644 --- a/src/wfc.erl +++ b/src/wfc.erl @@ -114,3 +114,7 @@ mul([Arg | Rest]) -> end; mul([]) -> {ok, wfc_sentence:one()}. + + +zero() -> wfc_sentence:zero(). +one() -> wfc_sentence:one(). diff --git a/src/wfc_bm.erl b/src/wfc_bm.erl index bf2081e..52b390d 100644 --- a/src/wfc_bm.erl +++ b/src/wfc_bm.erl @@ -27,6 +27,7 @@ blocks/1, %% fancier constructors from_list/1, bmt/1, + row/1, col/1, %% useful operations transpose/1, from_bitfun/2, to_list/1 @@ -117,7 +118,7 @@ rth(RowIdx1, {bm, _Shape = {rc, NR, NC}, Bits}) RowIdx0 = RowIdx1 - 1, RowLength = NC, SkipToGetToRow = RowIdx0 * RowLength, - <<_:SkipToGetToRow, RowBits:RowLength, _/bits>> = Bits, + <<_:SkipToGetToRow, RowBits:RowLength/bits, _/bits>> = Bits, {bm, NewShape, RowBits}. @@ -213,7 +214,8 @@ mulfold({rc, R, C}, Shape, AccBits, M1, M2) -> dot({bm, {rc, 1, Same}, Bits1}, {bm, {rc, Same, 1}, Bits2}) -> <> = Bits1, <> = Bits2, - SummandBits = Int1 band Int2, + SummandInt = Int1 band Int2, + SummandBits = <>, parity(SummandBits). @@ -322,6 +324,18 @@ bitsy([Bit | Rest], Acc) -> bitsy(Rest, <>); bitsy([], Result) -> Result. +-spec row([bit()]) -> bm(). + +row(Row) -> + from_list([Row]). + + +-spec col([bit()]) -> bm(). + +col(Col) -> + transpose(row(Col)). + + -spec bmt(Arity :: pos_integer()) -> bm(). % @doc Boole-Mobius transform % @@ -329,8 +343,8 @@ bitsy([], Result) -> Result. bmt(N) when N > 0 -> %% this might be backwards... - blocks([[bmt(N-1), bmt(N-1)], - [ztn(N-1), bmt(N-1)]]); + blocks([[bmt(N-1), ztn(N-1)], + [bmt(N-1), bmt(N-1)]]); bmt(0) -> from_list([[1]]). diff --git a/src/wfc_sftt.erl b/src/wfc_sftt.erl new file mode 100644 index 0000000..fe6a82b --- /dev/null +++ b/src/wfc_sftt.erl @@ -0,0 +1,149 @@ +% @doc +% sentence-fun <-> truth table logic +-module(wfc_sftt). + +-export_type([ + sf/0, tt/0 +]). + +-export([ + arity/1, + tt/1, sf/1, + sf_to_tt/1, tt_to_sf/1, + eval/2, + bfls/1, + bfl/2 +]). + +-type bit() :: 0 | 1. +-opaque sf() :: {sf, wfc_bm:bm()}. +-opaque tt() :: {tt, wfc_bm:bm()}. + +-spec arity(sf() | tt()) -> pos_integer(). + +arity({sf, BM}) -> matrix_arity(BM); +arity({tt, BM}) -> matrix_arity(BM). + +matrix_arity(Matrix) -> + {rc, Height, _} = wfc_bm:shape(Matrix), + log2(Height). + +log2(N) when N > 1 -> + 1 + log2(N div 2); +log2(1) -> + 0. + + +-spec sf_to_tt(sf()) -> tt(). +sf_to_tt({sf, SFBM}) -> + {tt, apply_bmt(SFBM)}. + + +-spec tt_to_sf(tt()) -> sf(). +tt_to_sf({tt, SFBM}) -> + {sf, apply_bmt(SFBM)}. + + +apply_bmt(Matrix) -> + BMT = wfc_bm:bmt(matrix_arity(Matrix)), + wfc_bm:mul(BMT, Matrix). + + +tt(List) -> + {tt, wfc_bm:col(List)}. + +sf(List) -> + {sf, wfc_bm:col(List)}. + + +-spec eval(sf() | tt(), [wfc:sentence()]) -> wfc:sentence(). + +eval(TT = {tt, _}, Sentences) -> + eval(tt_to_sf(TT), Sentences); +eval(SF = {sf, SFBM}, Sentences) -> + Arity = arity(SF), + Arity = length(Sentences), + % [0, 0, 0], [1, 0, 0], ... + BitFlagLists = bfls(Arity), + io:format("bfls: ~p~n", [BitFlagLists]), + % an SFBM is a Nx1 matrix where N = two_to_the(Arity) + % hacky but works + [Row] = wfc_bm:to_list(wfc_bm:transpose(SFBM)), + io:format("row: ~p~n", [Row]), + % filter by whether or not we're including + Included = filter_included(BitFlagLists, Row), + io:format("included: ~p~n", [Included]), + AlmostSummands = inseminate(Included, Sentences), + io:format("Almost: ~p~n", [AlmostSummands]), + collapse(AlmostSummands). + + +filter_included([_ | Rest], [0 | Rest2]) -> + filter_included(Rest, Rest2); +filter_included([Item | Rest], [1 | Rest2]) -> + [Item | filter_included(Rest, Rest2)]; +filter_included([], []) -> + []. + + +-spec collapse([[wfc:sentence()]]) -> wfc:sentence(). + +collapse(AlmostSummands) -> + Summands = lists:map(fun(Args) -> {ok,X} = wfc:mul(Args), X end, AlmostSummands), + {ok, Y} = wfc:add(Summands), + Y. + + +-spec inseminate(BFLs :: [[bit()]], Sentences :: [wfc:sentence()]) -> [[wfc:sentence()]]. + +inseminate(BFLs, Sentences) -> + lists:map(fun(BFL) -> inseminate2(BFL, Sentences) end, BFLs). + + +-spec inseminate2(BFL :: [bit()], Sentences :: [wfc:sentence()]) -> [wfc:sentence()]. +inseminate2(BFL, Sentences) -> + lists:zipwith(fun pair/2, BFL, Sentences). + +pair(0, _) -> wfc_sentence:one(); +pair(1, S) -> S. + + +-spec bfls(Arity :: non_neg_integer()) -> [[bit()]]. +% @doc get all bit-flag lists for 0..(2^Arity - 1) + +bfls(Arity) when Arity >= 0 -> + [bfl(Arity, N) || N <- lists:seq(0, two_to_the(Arity) - 1)]. + +two_to_the(N) -> + 1 bsl N. + + +-spec bfl(Length :: pos_integer(), N :: non_neg_integer()) -> [bit()]. +% @doc +% get the little-endian representation of N as binary, as a +% list of bits. + +bfl(Length, N) when Length > 0, N >= 0 -> + %% hacky but logically straightforward + bfl2(Length, lists:reverse(integer_to_list(N, 2))). + +%% we're chopping digits off the end here +bfl2(Length, Bits_Str) when Length =< length(Bits_Str) -> + bfl3(take(Length, Bits_Str)); +bfl2(Length, Bits_Str) when Length > length(Bits_Str) -> + % make more zeros than needed because about to circumcise + % them. + Zeros = [$0 || _ <- lists:seq(1, Length)], + bfl2(Length, Bits_Str ++ Zeros). + + +take(0, _) -> + []; +take(N, [Item | Rest]) when N >= 1 -> + [Item | take(N-1, Rest)]. + +bfl3(BitsText) -> + lists:map(fun unfuck_char/1, BitsText). + +unfuck_char($0) -> 0; +unfuck_char($1) -> 1. diff --git a/src/wfc_tts.erl b/src/wfc_tts.erl index 5992143..38dcd2d 100644 --- a/src/wfc_tts.erl +++ b/src/wfc_tts.erl @@ -24,8 +24,8 @@ ]). -type bit() :: 0 | 1. --type tt1() :: fun(( bit() ) -> bit() ). --type tt2() :: fun(( bit() ) -> bit)( ). +-type tt1() :: fun( (bit()) -> bit() ). +-type tt2() :: fun( (bit(), bit()) -> bit() ). %% convert truth tables to fixed-arity sentence-functions %% easiest approach is to use boole-mobius transform