32#include "access/htup_details.h"
33#include "access/xact.h"
34#include "catalog/pg_type.h"
35#include "executor/spi.h"
36#include "utils/array.h"
37#include "utils/builtins.h"
38#include "utils/resowner.h"
39#include "utils/uuid.h"
68int checkedArrayLength(ArrayType *arr,
const char *what)
72 if (ARR_NDIM(arr) > 1)
73 provsql_error(
"ucq_joint: %s must be a one-dimensional array", what);
76 return ARR_NDIM(arr) == 0 ? 0 : ARR_DIMS(arr)[0];
80const int32 *intArray(FunctionCallInfo fcinfo,
int argno,
const char *what,
83 ArrayType *a = PG_ARGISNULL(argno) ? NULL : PG_GETARG_ARRAYTYPE_P(argno);
84 len = checkedArrayLength(a, what);
85 return (a == NULL || len == 0) ? NULL : (
const int32 *) ARR_DATA_PTR(a);
103void decodeArgs(FunctionCallInfo fcinfo,
UCQ &ucq,
104 std::vector<FactRow> &rows)
106 int n_disj, n_ad, n_ar, n_av, n_aa;
107 const int32 *d_nvars = intArray(fcinfo, 0,
"disjunct_nvars", n_disj);
108 const int32 *a_disj = intArray(fcinfo, 1,
"atom_disjunct", n_ad);
109 const int32 *a_rel = intArray(fcinfo, 2,
"atom_rel", n_ar);
110 const int32 *a_vars = intArray(fcinfo, 3,
"atom_vars", n_av);
111 const int32 *a_arity = intArray(fcinfo, 4,
"atom_arity", n_aa);
115 if (n_ad != n_ar || n_ad != n_aa)
116 provsql_error(
"ucq_joint: atom arrays must have the same length");
119 for (
int d = 0; d < n_disj; ++d)
120 ucq.
disjuncts[d].n_vars =
static_cast<unsigned>(d_nvars[d]);
123 for (
int i = 0; i < n_ad; ++i) {
124 const int d = a_disj[i];
125 if (d < 0 || d >= n_disj)
126 provsql_error(
"ucq_joint: atom disjunct index out of range");
127 const int ar = a_arity[i];
128 if (ar < 0 || voff + ar > n_av)
129 provsql_error(
"ucq_joint: atom_vars shorter than declared arities");
131 atom.
relation_id =
static_cast<unsigned>(a_rel[i]);
132 atom.
vars.reserve(ar);
133 for (
int k = 0; k < ar; ++k)
134 atom.
vars.push_back(
static_cast<unsigned>(a_vars[voff + k]));
136 ucq.
disjuncts[d].atoms.push_back(std::move(atom));
139 int n_fr, n_fe, n_fa, n_fp, n_ft;
140 const int32 *f_rel = intArray(fcinfo, 5,
"fact_rel", n_fr);
141 const int32 *f_elems = intArray(fcinfo, 6,
"fact_elems", n_fe);
142 const int32 *f_arity = intArray(fcinfo, 7,
"fact_arity", n_fa);
143 ArrayType *toks = PG_ARGISNULL(8) ? NULL : PG_GETARG_ARRAYTYPE_P(8);
144 ArrayType *prbs = PG_ARGISNULL(9) ? NULL : PG_GETARG_ARRAYTYPE_P(9);
145 n_ft = checkedArrayLength(toks,
"fact_tokens");
146 n_fp = checkedArrayLength(prbs,
"fact_probs");
148 if (n_fr != n_fa || n_fr != n_ft || n_fr != n_fp)
149 provsql_error(
"ucq_joint: fact arrays must have the same length");
151 (toks && n_ft) ? (
const pg_uuid_t *) ARR_DATA_PTR(toks) : NULL;
152 const float8 *prob_data =
153 (prbs && n_fp) ? (
const float8 *) ARR_DATA_PTR(prbs) : NULL;
157 for (
int i = 0; i < n_fr; ++i) {
158 const int ar = f_arity[i];
159 if (ar < 0 || eoff + ar > n_fe)
160 provsql_error(
"ucq_joint: fact_elems shorter than declared arities");
164 for (
int k = 0; k < ar; ++k)
165 row.
elements.push_back(
static_cast<unsigned long>(f_elems[eoff + k]));
168 for (
int b = 0; b < 16; ++b)
169 if (tok_data[i].data[b] != 0)
173 row.
prob = prob_data[i];
174 rows.push_back(std::move(row));
182 std::vector<FactRow> rows;
183 decodeArgs(fcinfo, ucq, rows);
186 const unsigned max_tw =
188 const std::size_t max_states =
194 "ucq_joint: joint treewidth exceeds the configured maximum (%d); "
195 "fall back to the standard probability ladder",
207void decodeQuery(FunctionCallInfo fcinfo,
UCQ &ucq)
209 int n_disj, n_ad, n_ar, n_av, n_aa;
210 const int32 *d_nvars = intArray(fcinfo, 0,
"disjunct_nvars", n_disj);
211 const int32 *a_disj = intArray(fcinfo, 1,
"atom_disjunct", n_ad);
212 const int32 *a_rel = intArray(fcinfo, 2,
"atom_rel", n_ar);
213 const int32 *a_vars = intArray(fcinfo, 3,
"atom_vars", n_av);
214 const int32 *a_arity = intArray(fcinfo, 4,
"atom_arity", n_aa);
218 if (n_ad != n_ar || n_ad != n_aa)
219 provsql_error(
"ucq_joint: atom arrays must have the same length");
222 for (
int d = 0; d < n_disj; ++d)
223 ucq.
disjuncts[d].n_vars =
static_cast<unsigned>(d_nvars[d]);
226 for (
int i = 0; i < n_ad; ++i) {
227 const int d = a_disj[i];
228 if (d < 0 || d >= n_disj)
229 provsql_error(
"ucq_joint: atom disjunct index out of range");
230 const int ar = a_arity[i];
231 if (ar < 0 || voff + ar > n_av)
232 provsql_error(
"ucq_joint: atom_vars shorter than declared arities");
234 atom.
relation_id =
static_cast<unsigned>(a_rel[i]);
235 atom.
vars.reserve(ar);
236 for (
int k = 0; k < ar; ++k)
237 atom.
vars.push_back(
static_cast<unsigned>(a_vars[voff + k]));
239 ucq.
disjuncts[d].atoms.push_back(std::move(atom));
260 std::vector<SliceGate> slice;
261 std::map<std::string, int> uuid2node;
267 struct MulRef { std::string block;
unsigned value_index;
double prob; };
268 std::vector<MulRef> mulrefs;
269 std::vector<int> mul_resolved;
270 unsigned mulsb_counter = 0;
275 static constexpr int MULREF_BASE = -1000000;
278 if (children.empty())
280 int acc = children[0];
281 for (std::size_t i = 1; i < children.size(); ++i) {
284 s.
children = {
static_cast<unsigned>(acc),
285 static_cast<unsigned>(children[i])};
286 slice.push_back(std::move(s));
287 acc =
static_cast<int>(slice.size()) - 1;
292 int walk(
const GenericCircuit &gc,
gate_t g) {
293 const std::string u = gc.
getUUID(g);
295 auto it = uuid2node.find(u);
296 if (it != uuid2node.end())
306 slice.push_back(std::move(s));
307 res =
static_cast<int>(slice.size()) - 1;
321 if (r == -1) { cfalse =
true;
break; }
322 if (r == -2)
continue;
333 if (r == -2) { ctrue =
true;
break; }
334 if (r == -1)
continue;
343 throw JointCompilerException(
"malformed monus gate in circuit slice");
344 const int a = walk(gc, w[0]);
345 const int b = walk(gc, w[1]);
347 throw JointCompilerException(
348 "non-Boolean monus in circuit slice (only the negation "
349 "monus(one, x) is supported)");
350 if (b == -2) res = -1;
351 else if (b == -1) res = -2;
355 s.
children = {
static_cast<unsigned>(b)};
356 slice.push_back(std::move(s));
357 res =
static_cast<int>(slice.size()) - 1;
372 throw JointCompilerException(
"malformed mulinput gate (no key wire)");
373 const std::string key = gc.
getUUID(w[0]);
375 throw JointCompilerException(
376 "mulinput key gate has no UUID (cannot group the block)");
379 m.value_index = gc.
getInfos(g).first;
381 mulrefs.push_back(std::move(m));
382 res = MULREF_BASE -
static_cast<int>(mulrefs.size() - 1);
386 throw JointCompilerException(
387 "unsupported gate type in circuit slice (joint-width "
388 "compilation handles input/and/or/not and mulinput only)");
398 int emitInput(
double p) {
402 s.
token =
"\x01mulsb:" + std::to_string(mulsb_counter++);
403 slice.push_back(std::move(s));
404 return static_cast<int>(slice.size()) - 1;
408 int emitNot(
int child) {
411 s.
children = {
static_cast<unsigned>(child)};
412 slice.push_back(std::move(s));
413 return static_cast<int>(slice.size()) - 1;
422 void expandRec(
const std::vector<int> &idxs,
const std::vector<double> &cum,
423 unsigned start,
unsigned end, std::vector<int> &prefix) {
425 mul_resolved[idxs[start]] =
426 prefix.empty() ? emitInput(1.0)
430 const unsigned mid = (start + end) / 2;
431 const double prev_start = (start == 0) ? 0. : cum[start - 1];
432 const int g = emitInput((cum[mid] - prev_start) / (cum[end] - prev_start));
433 const int ng = emitNot(g);
435 expandRec(idxs, cum, start, mid, prefix);
437 prefix.push_back(ng);
438 expandRec(idxs, cum, mid + 1, end, prefix);
446 void expandMulBlocks() {
449 mul_resolved.assign(mulrefs.size(), -1);
450 std::map<std::string, std::vector<int>> by_block;
451 for (
int i = 0; i < static_cast<int>(mulrefs.size()); ++i)
452 by_block[mulrefs[i].block].push_back(i);
454 for (
auto &kv : by_block) {
455 std::vector<int> &idxs = kv.second;
456 std::sort(idxs.begin(), idxs.end(), [&](
int a,
int b) {
457 return mulrefs[a].value_index < mulrefs[b].value_index;
459 const unsigned n =
static_cast<unsigned>(idxs.size());
460 std::vector<double> cum(n);
462 for (
unsigned i = 0; i < n; ++i) {
463 c += mulrefs[idxs[i]].prob;
466 std::vector<int> prefix;
470 constexpr double eps = std::numeric_limits<double>::epsilon() * 10;
471 if (cum[n - 1] < 1. - eps)
472 prefix.push_back(emitInput(cum[n - 1]));
473 expandRec(idxs, cum, 0, n - 1, prefix);
477 for (SliceGate &sg : slice)
478 for (
unsigned &ch : sg.children) {
479 const int ci =
static_cast<int>(ch);
480 if (ci <= MULREF_BASE)
481 ch =
static_cast<unsigned>(mul_resolved[MULREF_BASE - ci]);
487 int resolveCode(
int code)
const {
488 if (code <= MULREF_BASE)
489 return mul_resolved[MULREF_BASE - code];
506void buildTrackedFactsArrays(
const int32 *f_rel,
int n_fr,
507 const int32 *f_elems,
int n_fe,
508 const int32 *f_arity,
int n_fa,
510 std::vector<Fact> &facts,
511 std::vector<SliceGate> &slice,
512 unsigned long &n_elements,
bool &has_internal)
514 if (n_fr != n_fa || n_fr != n_ft)
515 provsql_error(
"ucq_joint: fact arrays must have the same length");
522 std::vector<std::pair<Fact, int>> pending;
523 pending.reserve(n_fr);
526 for (
int i = 0; i < n_fr; ++i) {
527 const int ar = f_arity[i];
528 if (ar < 0 || eoff + ar > n_fe)
529 provsql_error(
"ucq_joint: fact_elems shorter than declared arities");
532 for (
int k = 0; k < ar; ++k) {
533 unsigned long e =
static_cast<unsigned long>(f_elems[eoff + k]);
535 n_elements = std::max(n_elements, e + 1);
541 pending.emplace_back(std::move(f), node);
544 sb.expandMulBlocks();
547 facts.reserve(pending.size());
548 for (
auto &pf : pending) {
549 const int node = sb.resolveCode(pf.second);
557 f.
gate =
static_cast<std::size_t
>(node);
559 facts.push_back(std::move(f));
562 has_internal =
false;
563 for (
const auto &sg : sb.slice)
568 slice = std::move(sb.slice);
572void buildTrackedFacts(FunctionCallInfo fcinfo,
int base,
573 std::vector<Fact> &facts, std::vector<SliceGate> &slice,
574 unsigned long &n_elements,
bool &has_internal)
576 int n_fr, n_fe, n_fa, n_ft;
577 const int32 *f_rel = intArray(fcinfo, base,
"fact_rel", n_fr);
578 const int32 *f_elems = intArray(fcinfo, base + 1,
"fact_elems", n_fe);
579 const int32 *f_arity = intArray(fcinfo, base + 2,
"fact_arity", n_fa);
581 PG_ARGISNULL(base + 3) ? NULL : PG_GETARG_ARRAYTYPE_P(base + 3);
582 n_ft = checkedArrayLength(toks,
"fact_tokens");
584 (toks && n_ft) ? (
const pg_uuid_t *) ARR_DATA_PTR(toks) : NULL;
585 buildTrackedFactsArrays(f_rel, n_fr, f_elems, n_fe, f_arity, n_fa,
586 tok_data, n_ft, facts, slice, n_elements, has_internal);
599std::map<std::vector<unsigned long>,
pg_uuid_t> materializeAnswersSingleDP(
600 const UCQ &ucq,
const std::vector<unsigned> &head_vars,
601 const int32 *f_rel,
int n_fr,
const int32 *f_elems,
int n_fe,
602 const int32 *f_arity,
int n_fa,
const pg_uuid_t *tok_data,
int n_ft)
604 std::vector<Fact> facts;
605 std::vector<SliceGate> slice;
606 unsigned long n_elements;
608 buildTrackedFactsArrays(f_rel, n_fr, f_elems, n_fe, f_arity, n_fa,
609 tok_data, n_ft, facts, slice, n_elements, has_internal);
614 const std::size_t max_states =
620 std::vector<gate_t> roots;
621 roots.reserve(circ.
answers.size());
622 for (
const auto &a : circ.
answers)
623 roots.push_back(a.root);
626 std::map<std::vector<unsigned long>,
pg_uuid_t> out;
627 for (
const auto &a : circ.
answers)
628 out[a.head] = uuid_of.at(a.root);
636 decodeQuery(fcinfo, ucq);
638 std::vector<Fact> facts;
639 std::vector<SliceGate> slice;
640 unsigned long n_elements;
642 buildTrackedFacts(fcinfo, 5, facts, slice, n_elements, has_internal);
645 const std::size_t max_states =
658 std::vector<FactRow> rows;
659 rows.reserve(facts.size());
660 for (
const auto &f : facts) {
668 rows.push_back(std::move(row));
676 "ucq_joint: data treewidth exceeds the configured maximum (%d); "
677 "fall back to the standard probability ladder",
693 "ucq_joint: joint treewidth exceeds the configured maximum (%d); "
694 "fall back to the standard probability ladder",
711 auto result = runFromArgs(fcinfo);
714 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
715 provsql_error(
"ucq_joint_compile_stats: expected composite return type");
716 tupdesc = BlessTupleDesc(tupdesc);
719 bool nulls[8] = {
false,
false,
false,
false,
false,
false,
false,
false};
720 values[0] = Float8GetDatum(result.dd.probabilityEvaluation());
721 values[1] = Int32GetDatum(
static_cast<int32
>(result.stats.joint_treewidth));
722 values[2] = Int32GetDatum(
static_cast<int32
>(result.stats.data_treewidth_lb));
723 values[3] = Int32GetDatum(
static_cast<int32
>(result.stats.circuit_treewidth_lb));
724 values[4] = Int64GetDatum(
static_cast<int64
>(result.stats.nb_bags));
725 values[5] = Int64GetDatum(
static_cast<int64
>(result.stats.max_states));
726 values[6] = Int64GetDatum(
static_cast<int64
>(result.stats.dd_size));
727 unsigned maxenum = 0;
728 for (
unsigned ev : result.stats.n_enumerating)
731 values[7] = Int32GetDatum(
static_cast<int32
>(maxenum));
733 PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
734 }
catch (
const std::exception &e) {
759 auto result = runTrackedFromArgs(fcinfo);
763 *u = uuid_of.at(result.dd.getRoot());
765 }
catch (
const std::exception &e) {
783 auto result = runTrackedFromArgs(fcinfo);
786 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
787 provsql_error(
"ucq_joint_compile_stats: expected composite return type");
788 tupdesc = BlessTupleDesc(tupdesc);
791 bool nulls[8] = {
false,
false,
false,
false,
false,
false,
false,
false};
792 values[0] = Float8GetDatum(result.dd.probabilityEvaluation());
793 values[1] = Int32GetDatum(
static_cast<int32
>(result.stats.joint_treewidth));
794 values[2] = Int32GetDatum(
static_cast<int32
>(result.stats.data_treewidth_lb));
795 values[3] = Int32GetDatum(
static_cast<int32
>(result.stats.circuit_treewidth_lb));
796 values[4] = Int64GetDatum(
static_cast<int64
>(result.stats.nb_bags));
797 values[5] = Int64GetDatum(
static_cast<int64
>(result.stats.max_states));
798 values[6] = Int64GetDatum(
static_cast<int64
>(result.stats.dd_size));
799 unsigned maxenum = 0;
800 for (
unsigned ev : result.stats.n_enumerating)
803 values[7] = Int32GetDatum(
static_cast<int32
>(maxenum));
805 PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
806 }
catch (
const std::exception &e) {
829struct JwAnswerCache {
830 bool declined =
false;
831 std::vector<std::string> keys;
832 std::vector<pg_uuid_t> tokens;
836void jwAnswerCacheDelete(
void *arg)
838 delete reinterpret_cast<JwAnswerCache *
>(arg);
842std::string jwHeadKey(
const std::vector<std::string> &vals)
845 for (
const auto &v : vals) { k += v; k.push_back(
'\x1f'); }
862 const std::vector<unsigned> &head_vars,
863 JwAnswerCache *
cache)
866 Oid argt[1] = { JSONBOID };
867 Datum argv[1] = { descriptor };
868 char argn[1] = {
' ' };
869 const int rc = SPI_execute_with_args(
870 "SELECT * FROM provsql.ucq_joint_gather($1)", 1, argt, argv, argn,
true, 1);
871 if (rc != SPI_OK_SELECT || SPI_processed != 1) {
876 std::vector<std::string> keys;
877 std::vector<pg_uuid_t> tokens;
880 TupleDesc td = SPI_tuptable->tupdesc;
881 HeapTuple row = SPI_tuptable->vals[0];
883 auto intArr = [&](
int col,
int &n) ->
const int32 * {
884 Datum dd = SPI_getbinval(row, td, col, &isnull);
885 if (isnull) { n = 0;
return nullptr; }
886 ArrayType *a = DatumGetArrayTypeP(dd);
887 n = ArrayGetNItems(ARR_NDIM(a), ARR_DIMS(a));
888 return (
const int32 *) ARR_DATA_PTR(a);
890 int n_dnv, n_adisj, n_arel, n_avars, n_aarity, n_frel, n_felems, n_farity;
891 const int32 *dnv = intArr(1, n_dnv);
892 const int32 *adisj = intArr(2, n_adisj);
893 const int32 *arel = intArr(3, n_arel);
894 const int32 *avars = intArr(4, n_avars);
895 const int32 *aarity = intArr(5, n_aarity);
896 const int32 *frel = intArr(6, n_frel);
897 const int32 *felems = intArr(7, n_felems);
898 const int32 *farity = intArr(8, n_farity);
899 Datum dtok = SPI_getbinval(row, td, 9, &isnull);
900 ArrayType *atok = isnull ? nullptr : DatumGetArrayTypeP(dtok);
901 const int n_ftok = atok ? ArrayGetNItems(ARR_NDIM(atok), ARR_DIMS(atok)) : 0;
903 atok ? (
const pg_uuid_t *) ARR_DATA_PTR(atok) :
nullptr;
905 std::vector<std::string> val_by_id;
906 Datum dval = SPI_getbinval(row, td, 10, &isnull);
908 ArrayType *aval = DatumGetArrayTypeP(dval);
909 Datum *elems;
bool *nulls;
int nval;
910 deconstruct_array(aval, TEXTOID, -1,
false,
TYPALIGN_INT,
911 &elems, &nulls, &nval);
912 val_by_id.resize(nval);
913 for (
int i = 0; i < nval; ++i)
914 val_by_id[i] = nulls[i] ? std::string() : TextDatumGetCString(elems[i]);
919 for (
int d = 0; d < n_dnv; ++d)
920 ucq.
disjuncts[d].n_vars =
static_cast<unsigned>(dnv[d]);
922 for (
int i = 0; i < n_adisj; ++i) {
923 const int dd = adisj[i];
924 const int ar = aarity[i];
927 for (
int k = 0; k < ar; ++k)
928 atom.
vars.push_back(
static_cast<unsigned>(avars[voff + k]));
930 ucq.
disjuncts[dd].atoms.push_back(std::move(atom));
933 const auto answers = materializeAnswersSingleDP(
934 ucq, head_vars, frel, n_frel, felems, n_felems, farity, n_farity,
936 keys.reserve(answers.size());
937 tokens.reserve(answers.size());
938 for (
const auto &kv : answers) {
939 std::vector<std::string> txt;
940 txt.reserve(kv.first.size());
941 for (
unsigned long id : kv.first)
942 txt.push_back(
id < val_by_id.size() ? val_by_id[
id] : std::string());
943 keys.push_back(jwHeadKey(txt));
944 tokens.push_back(kv.second);
951 cache->keys = std::move(keys);
952 cache->tokens = std::move(tokens);
963 JwAnswerCache *
cache =
964 reinterpret_cast<JwAnswerCache *
>(fcinfo->flinfo->fn_extra);
966 if (
cache ==
nullptr) {
968 MemoryContext fnctx = fcinfo->flinfo->fn_mcxt;
969 cache =
new JwAnswerCache();
970 MemoryContextCallback *cb = (MemoryContextCallback *)
971 MemoryContextAllocZero(fnctx,
sizeof(MemoryContextCallback));
972 cb->func = jwAnswerCacheDelete;
974 MemoryContextRegisterResetCallback(fnctx, cb);
975 fcinfo->flinfo->fn_extra =
cache;
977 if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) {
978 cache->declined =
true;
980 std::vector<unsigned> head_vars;
982 ArrayType *a = PG_GETARG_ARRAYTYPE_P(1);
983 const int32 *d = (
const int32 *) ARR_DATA_PTR(a);
984 const int n = ArrayGetNItems(ARR_NDIM(a), ARR_DIMS(a));
985 for (
int i = 0; i < n; ++i)
986 head_vars.push_back(
static_cast<unsigned>(d[i]));
988 const Datum desc = PG_GETARG_DATUM(0);
993 MemoryContext oldcxt = CurrentMemoryContext;
994 ResourceOwner oldowner = CurrentResourceOwner;
995 BeginInternalSubTransaction(NULL);
999 cache->declined =
true;
1000 ReleaseCurrentSubTransaction();
1001 MemoryContextSwitchTo(oldcxt);
1002 CurrentResourceOwner = oldowner;
1006 MemoryContextSwitchTo(oldcxt);
1007 RollbackAndReleaseCurrentSubTransaction();
1008 MemoryContextSwitchTo(oldcxt);
1009 CurrentResourceOwner = oldowner;
1011 cache->declined =
true;
1012 cache->keys.clear();
1013 cache->tokens.clear();
1020 if (!
cache->declined && !PG_ARGISNULL(2)) {
1021 std::vector<std::string> hv;
1022 ArrayType *a = PG_GETARG_ARRAYTYPE_P(2);
1023 Datum *elems;
bool *nulls;
int n;
1024 deconstruct_array(a, TEXTOID, -1,
false,
TYPALIGN_INT, &elems, &nulls, &n);
1025 for (
int i = 0; i < n; ++i)
1026 hv.push_back(nulls[i] ? std::string() : TextDatumGetCString(elems[i]));
1027 const std::string key = jwHeadKey(hv);
1028 for (std::size_t i = 0; i <
cache->keys.size(); ++i)
1029 if (
cache->keys[i] == key) {
1031 *u =
cache->tokens[i];
1032 PG_RETURN_UUID_P(u);
1037 if (PG_ARGISNULL(3))
1039 PG_RETURN_DATUM(PG_GETARG_DATUM(3));
@ AND
Boolean AND aggregate.
std::unordered_map< gate_t, pg_uuid_t, hash_gate_t > materializeCertifiedDD(const dDNNF &dd, const std::vector< gate_t > &roots)
Materialise (the reachable part of) a certified d-D into the mmap store.
Content-addressed materialisation of a certified d-D into the mmap provenance store.
static CircuitCache cache
Process-local singleton circuit gate cache.
GenericCircuit getGenericCircuit(pg_uuid_t token)
Build a GenericCircuit from the mmap store rooted at token.
Build in-memory circuits from the mmap-backed persistent store.
gate_t
Strongly-typed gate identifier.
Semiring-agnostic in-memory provenance circuit.
Phase A of the joint-width UCQ compiler: assemble the joint graph of the data and its correlation str...
SliceGateType
Gate kind of a circuit-slice node (correlated regime).
@ GATE
Present iff its slice gate evaluates true (correlated regime).
@ CERTAIN
Always present: an untracked relation, constant-true token.
Phase C of the joint-width UCQ compiler: a UCQ-specialised homomorphism-type DP that runs directly ov...
Fix macro conflicts between PostgreSQL headers and the C++ STL/Boost.
std::vector< gate_t > & getWires(gate_t g)
Return a mutable reference to the child-wire list of gate g.
gateType getGateType(gate_t g) const
Return the type of gate g.
uuid getUUID(gate_t g) const
Return the UUID string associated with gate g.
gate_t getGate(const uuid &u)
Return (or create) the gate associated with UUID u.
In-memory provenance circuit with semiring-generic evaluation.
double getProb(gate_t g) const
Return the probability for gate g.
std::pair< unsigned, unsigned > getInfos(gate_t g) const
Return the integer annotation pair for gate g.
Exception thrown when joint-width compilation cannot proceed.
The joint encoding of an instance: facts, world events, and the joint graph the screen and the DP run...
static JointEncoding fromCorrelated(std::vector< Fact > facts, std::vector< SliceGate > slice, unsigned long n_elements)
Construct the correlated-regime encoding from facts and an already-extracted circuit slice.
static JointEncoding fromFacts(const std::vector< FactRow > &rows)
Build the data-graph (§3.5 fast path) encoding from raw rows.
Exception thrown when a tree decomposition cannot be constructed.
static AnswerCircuit compileAnswersOneDP(const JointEncoding &enc, const UCQ &ucq, const std::vector< unsigned > &head_vars, unsigned max_treewidth=TreeDecomposition::MAX_TREEWIDTH, std::size_t max_states=DEFAULT_MAX_STATES)
static Result compile(const JointEncoding &enc, const UCQ &ucq, unsigned max_treewidth=TreeDecomposition::MAX_TREEWIDTH, std::size_t max_states=DEFAULT_MAX_STATES)
Compile a Boolean UCQ over enc into a certified d-D.
PostgreSQL cross-version compatibility shims for ProvSQL.
#define TYPALIGN_INT
Alignment codes for the array routines (construct_array / deconstruct_array).
int provsql_joint_max_states
Per-bag DP state-count cap of the joint-width UCQ compiler (the true safety net); provsql....
int provsql_joint_max_treewidth
Maximum joint treewidth the joint-width UCQ compiler attempts before declining (caller falls back to ...
#define provsql_error(fmt,...)
Report a fatal ProvSQL error and abort the current transaction.
Core types, constants, and utilities shared across ProvSQL.
string uuid2string(pg_uuid_t uuid)
Format a pg_uuid_t as a std::string.
C++ utility functions for UUID manipulation.
One atom of a conjunctive query: a relation symbol applied to query variables.
std::vector< unsigned > vars
Query-variable indices, one per column.
unsigned relation_id
Dense id of the relation symbol.
One row of an atom's relation, as handed in by the SQL layer.
unsigned relation_id
Dense id of the relation symbol.
double prob
Tuple probability (for an independent gate_input token).
std::string token
Provenance gate (UUID); empty marks a certain (untracked) fact.
std::vector< unsigned long > elements
Dense ids of the row's domain elements.
A deduplicated fact participating in the DP.
std::size_t gate
Index into slice (when GATE).
std::vector< unsigned long > elements
Dense element ids (the fact's tuple).
FactGateKind kind
How the fact's presence is gated.
unsigned relation_id
Dense id of the relation symbol.
SliceGateType type
Node kind.
std::vector< unsigned > children
Child slice indices (≤ 2; empty for INPUT).
double prob
Marginal (INPUT only).
std::string token
Provenance token of the leaf (INPUT only; for the d-D IN gate UUID).
dDNNF dd
The shared certified d-D.
std::vector< AnswerRoot > answers
One root per discovered answer.
A compiled UCQ: the d-D and its statistics.
A union of conjunctive queries.
std::vector< CQ > disjuncts
The disjuncts (at least one).
Datum ucq_joint_compile_stats(PG_FUNCTION_ARGS)
PostgreSQL-callable entry point: UCQ probability plus compilation statistics (the three width columns...
static bool jwComputeCache(Datum descriptor, const std::vector< unsigned > &head_vars, JwAnswerCache *cache)
Gather + single-DP materialise all answers into cache.
Datum ucq_joint_compile_stats_tracked(PG_FUNCTION_ARGS)
PostgreSQL-callable entry point: correlated UCQ probability plus compilation statistics (the three wi...
Datum ucq_joint_materialize_tracked(PG_FUNCTION_ARGS)
PostgreSQL-callable entry point: compile the UCQ over correlated inputs and materialise its certified...
Datum ucq_joint_provenance_answer(PG_FUNCTION_ARGS)
Per-answer joint-width provenance via the single top-down DP.