\set ECHO none \pset format unaligned -- Columnar internals of the bounded-treewidth reachability route: -- reachability_evaluate / reachability_compile_stats compile s-t -- reachability along a tree decomposition of the *data* graph (the -- provenance refinement of Courcelle's theorem) into a d-DNNF that is -- deterministic and decomposable by construction, of size linear in the -- number of edges for fixed data treewidth -- exact and linear-time on -- cyclic graphs as well. The user-facing route is an ordinary -- WITH RECURSIVE reachability query under provsql.boolean_provenance -- (see the btw_recursive test, PG15+); these columnar forms take -- parallel arrays and are exercised here version-independently with -- closed-form checks. -- Helper: a chain of n edges with probability p, as columnar arrays. CREATE OR REPLACE FUNCTION btw_chain_prob(n int, p float8) RETURNS float8 AS $$ SELECT reachability_evaluate( (SELECT array_agg(i) FROM generate_series(1,n) i), (SELECT array_agg(i+1) FROM generate_series(1,n) i), (SELECT array_agg(public.uuid_generate_v5(uuid_ns_provsql(), 'btwchain'||i)) FROM generate_series(1,n) i), (SELECT array_agg(p) FROM generate_series(1,n) i), 1, n+1, true); $$ LANGUAGE sql; -- Series: p^n. SELECT round(btw_chain_prob(20, 0.9)::numeric, 6) AS series_20, round(0.9^20, 6) AS expected; -- Parallel edges: 1 - (1-p)^3. SELECT round(reachability_evaluate( ARRAY[1,1,1], ARRAY[2,2,2], ARRAY['11111111-1111-1111-1111-111111111111', '22222222-2222-2222-2222-222222222222', '33333333-3333-3333-3333-333333333333']::uuid[], ARRAY[0.5,0.5,0.5], 1, 2, true)::numeric, 6) AS parallel_3; -- Undirected triangle: P(a ~ c) = P(ac) + (1-P(ac)) P(ab) P(bc) = 0.625. SELECT round(reachability_evaluate( ARRAY[1,2,1], ARRAY[2,3,3], ARRAY['11111111-1111-1111-1111-111111111111', '22222222-2222-2222-2222-222222222222', '33333333-3333-3333-3333-333333333333']::uuid[], ARRAY[0.5,0.5,0.5], 1, 3, false)::numeric, 6) AS triangle_undirected; -- The same undirected edge encoded as a mutual-reverse pair of arcs -- sharing their provenance token. SELECT round(reachability_evaluate( ARRAY[1,2, 2,3, 1,3], ARRAY[2,1, 3,2, 3,1], ARRAY['11111111-1111-1111-1111-111111111111','11111111-1111-1111-1111-111111111111', '22222222-2222-2222-2222-222222222222','22222222-2222-2222-2222-222222222222', '33333333-3333-3333-3333-333333333333','33333333-3333-3333-3333-333333333333']::uuid[], ARRAY[0.5,0.5, 0.5,0.5, 0.5,0.5], 1, 3, true)::numeric, 6) AS triangle_reverse_pairs; -- Cyclic graph (cf. the recursive test): reach(4) = 0.7416, exactly, -- with no fixpoint machinery. SELECT round(reachability_evaluate( ARRAY[1,2,3,2,3], ARRAY[2,3,2,4,4], ARRAY['11111111-1111-1111-1111-111111111111', '22222222-2222-2222-2222-222222222222', '33333333-3333-3333-3333-333333333333', '44444444-4444-4444-4444-444444444444', '55555555-5555-5555-5555-555555555555']::uuid[], ARRAY[0.9,0.8,0.5,0.6,0.7], 1, 4, true)::numeric, 6) AS cyclic_directed; -- Trivial cases. SELECT round(reachability_evaluate(NULL,NULL,NULL,NULL, 1, 1, true)::numeric, 6) AS source_equals_target; SELECT round(reachability_evaluate(NULL,NULL,NULL,NULL, 1, 2, true)::numeric, 6) AS no_edges; -- Compilation statistics on a 2 x 30 ladder (treewidth 2), undirected: -- the emitted d-DNNF stays linear in the edge count; the structural -- counters are heuristic- and platform-dependent, so only sanity bounds -- are printed. WITH edges AS ( SELECT 2*i+1 AS s, 2*i+3 AS d, 0.9::float8 AS p, public.uuid_generate_v5(uuid_ns_provsql(), 'btwlad-t'||i) AS tok FROM generate_series(0,28) i UNION ALL SELECT 2*i+2, 2*i+4, 0.9, public.uuid_generate_v5(uuid_ns_provsql(), 'btwlad-b'||i) FROM generate_series(0,28) i UNION ALL SELECT 2*i+1, 2*i+2, 0.5, public.uuid_generate_v5(uuid_ns_provsql(), 'btwlad-r'||i) FROM generate_series(0,29) i ) SELECT data_treewidth, nb_variables, nb_gates < 100 * nb_variables AS gates_linear, max_states <= 32 AS states_bounded, round(probability::numeric, 6) AS probability FROM edges, LATERAL (SELECT array_agg(s) ss, array_agg(d) dd, array_agg(tok) tt, array_agg(p) pp FROM edges) arr, reachability_compile_stats(arr.ss, arr.dd, arr.tt, arr.pp, 1, 60, false) LIMIT 1; -- Error paths. \set VERBOSITY terse -- Data treewidth above the supported limit (K14 has treewidth 13). SELECT reachability_evaluate( (SELECT array_agg(i) FROM generate_series(1,14) i, generate_series(1,14) j WHERE i < j), (SELECT array_agg(j) FROM generate_series(1,14) i, generate_series(1,14) j WHERE i < j), (SELECT array_agg(public.uuid_generate_v5(uuid_ns_provsql(), 'k14-'||i||'-'||j)) FROM generate_series(1,14) i, generate_series(1,14) j WHERE i < j), (SELECT array_agg(0.5::float8) FROM generate_series(1,14) i, generate_series(1,14) j WHERE i < j), 1, 14, false); -- A token shared by edges that are not mutual reverses. SELECT reachability_evaluate( ARRAY[1,2], ARRAY[2,3], ARRAY['11111111-1111-1111-1111-111111111111', '11111111-1111-1111-1111-111111111111']::uuid[], ARRAY[0.5,0.5], 1, 3, true); -- Mismatched array lengths. SELECT reachability_evaluate(ARRAY[1], ARRAY[2,3], ARRAY['11111111-1111-1111-1111-111111111111']::uuid[], ARRAY[0.5], 1, 2, true); \set VERBOSITY default DROP FUNCTION btw_chain_prob(int, float8);