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 std::string mulsb_sig;
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)");
407 int emitInput(
double p,
const std::string &tag) {
411 s.
token =
"\x01mulsb:" + tag;
412 slice.push_back(std::move(s));
413 return static_cast<int>(slice.size()) - 1;
417 int emitNot(
int child) {
420 s.
children = {
static_cast<unsigned>(child)};
421 slice.push_back(std::move(s));
422 return static_cast<int>(slice.size()) - 1;
431 void expandRec(
const std::vector<int> &idxs,
const std::vector<double> &cum,
432 unsigned start,
unsigned end, std::vector<int> &prefix) {
434 mul_resolved[idxs[start]] =
435 prefix.empty() ? emitInput(1.0, mulsb_sig +
":sole")
439 const unsigned mid = (start + end) / 2;
440 const double prev_start = (start == 0) ? 0. : cum[start - 1];
441 const int g = emitInput((cum[mid] - prev_start) / (cum[end] - prev_start),
442 mulsb_sig +
":" + std::to_string(start) +
"-"
443 + std::to_string(end));
444 const int ng = emitNot(g);
446 expandRec(idxs, cum, start, mid, prefix);
448 prefix.push_back(ng);
449 expandRec(idxs, cum, mid + 1, end, prefix);
457 void expandMulBlocks() {
460 mul_resolved.assign(mulrefs.size(), -1);
461 std::map<std::string, std::vector<int>> by_block;
462 for (
int i = 0; i < static_cast<int>(mulrefs.size()); ++i)
463 by_block[mulrefs[i].block].push_back(i);
465 for (
auto &kv : by_block) {
466 std::vector<int> &idxs = kv.second;
467 std::sort(idxs.begin(), idxs.end(), [&](
int a,
int b) {
468 return mulrefs[a].value_index < mulrefs[b].value_index;
470 const unsigned n =
static_cast<unsigned>(idxs.size());
471 std::vector<double> cum(n);
473 for (
unsigned i = 0; i < n; ++i) {
474 c += mulrefs[idxs[i]].prob;
480 mulsb_sig = kv.first;
481 for (
unsigned i = 0; i < n; ++i)
482 mulsb_sig +=
":" + std::to_string(mulrefs[idxs[i]].value_index) +
"="
483 + std::to_string(mulrefs[idxs[i]].prob);
485 std::vector<int> prefix;
489 constexpr double eps = std::numeric_limits<double>::epsilon() * 10;
490 if (cum[n - 1] < 1. - eps)
491 prefix.push_back(emitInput(cum[n - 1], mulsb_sig +
":active"));
492 expandRec(idxs, cum, 0, n - 1, prefix);
496 for (SliceGate &sg : slice)
497 for (
unsigned &ch : sg.children) {
498 const int ci =
static_cast<int>(ch);
499 if (ci <= MULREF_BASE)
500 ch =
static_cast<unsigned>(mul_resolved[MULREF_BASE - ci]);
506 int resolveCode(
int code)
const {
507 if (code <= MULREF_BASE)
508 return mul_resolved[MULREF_BASE - code];
525void buildTrackedFactsArrays(
const int32 *f_rel,
int n_fr,
526 const int32 *f_elems,
int n_fe,
527 const int32 *f_arity,
int n_fa,
529 std::vector<Fact> &facts,
530 std::vector<SliceGate> &slice,
531 unsigned long &n_elements,
bool &has_internal)
533 if (n_fr != n_fa || n_fr != n_ft)
534 provsql_error(
"ucq_joint: fact arrays must have the same length");
541 std::vector<std::pair<Fact, int>> pending;
542 pending.reserve(n_fr);
545 for (
int i = 0; i < n_fr; ++i) {
546 const int ar = f_arity[i];
547 if (ar < 0 || eoff + ar > n_fe)
548 provsql_error(
"ucq_joint: fact_elems shorter than declared arities");
551 for (
int k = 0; k < ar; ++k) {
552 unsigned long e =
static_cast<unsigned long>(f_elems[eoff + k]);
554 n_elements = std::max(n_elements, e + 1);
560 pending.emplace_back(std::move(f), node);
563 sb.expandMulBlocks();
566 facts.reserve(pending.size());
567 for (
auto &pf : pending) {
568 const int node = sb.resolveCode(pf.second);
576 f.
gate =
static_cast<std::size_t
>(node);
578 facts.push_back(std::move(f));
581 has_internal =
false;
582 for (
const auto &sg : sb.slice)
587 slice = std::move(sb.slice);
591void buildTrackedFacts(FunctionCallInfo fcinfo,
int base,
592 std::vector<Fact> &facts, std::vector<SliceGate> &slice,
593 unsigned long &n_elements,
bool &has_internal)
595 int n_fr, n_fe, n_fa, n_ft;
596 const int32 *f_rel = intArray(fcinfo, base,
"fact_rel", n_fr);
597 const int32 *f_elems = intArray(fcinfo, base + 1,
"fact_elems", n_fe);
598 const int32 *f_arity = intArray(fcinfo, base + 2,
"fact_arity", n_fa);
600 PG_ARGISNULL(base + 3) ? NULL : PG_GETARG_ARRAYTYPE_P(base + 3);
601 n_ft = checkedArrayLength(toks,
"fact_tokens");
603 (toks && n_ft) ? (
const pg_uuid_t *) ARR_DATA_PTR(toks) : NULL;
604 buildTrackedFactsArrays(f_rel, n_fr, f_elems, n_fe, f_arity, n_fa,
605 tok_data, n_ft, facts, slice, n_elements, has_internal);
618std::map<std::vector<unsigned long>,
pg_uuid_t> materializeAnswersSingleDP(
619 const UCQ &ucq,
const std::vector<unsigned> &head_vars,
620 const int32 *f_rel,
int n_fr,
const int32 *f_elems,
int n_fe,
621 const int32 *f_arity,
int n_fa,
const pg_uuid_t *tok_data,
int n_ft)
623 std::vector<Fact> facts;
624 std::vector<SliceGate> slice;
625 unsigned long n_elements;
627 buildTrackedFactsArrays(f_rel, n_fr, f_elems, n_fe, f_arity, n_fa,
628 tok_data, n_ft, facts, slice, n_elements, has_internal);
633 const std::size_t max_states =
639 std::vector<gate_t> roots;
640 roots.reserve(circ.
answers.size());
641 for (
const auto &a : circ.
answers)
642 roots.push_back(a.root);
646 std::map<std::vector<unsigned long>,
pg_uuid_t> out;
647 for (
const auto &a : circ.
answers)
648 out[a.head] = uuid_of.at(a.root);
656 decodeQuery(fcinfo, ucq);
658 std::vector<Fact> facts;
659 std::vector<SliceGate> slice;
660 unsigned long n_elements;
662 buildTrackedFacts(fcinfo, 5, facts, slice, n_elements, has_internal);
665 const std::size_t max_states =
678 std::vector<FactRow> rows;
679 rows.reserve(facts.size());
680 for (
const auto &f : facts) {
688 rows.push_back(std::move(row));
696 "ucq_joint: data treewidth exceeds the configured maximum (%d); "
697 "fall back to the standard probability ladder",
713 "ucq_joint: joint treewidth exceeds the configured maximum (%d); "
714 "fall back to the standard probability ladder",
731 auto result = runFromArgs(fcinfo);
734 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
735 provsql_error(
"ucq_joint_compile_stats: expected composite return type");
736 tupdesc = BlessTupleDesc(tupdesc);
739 bool nulls[8] = {
false,
false,
false,
false,
false,
false,
false,
false};
740 values[0] = Float8GetDatum(result.dd.probabilityEvaluation());
741 values[1] = Int32GetDatum(
static_cast<int32
>(result.stats.joint_treewidth));
742 values[2] = Int32GetDatum(
static_cast<int32
>(result.stats.data_treewidth_lb));
743 values[3] = Int32GetDatum(
static_cast<int32
>(result.stats.circuit_treewidth_lb));
744 values[4] = Int64GetDatum(
static_cast<int64
>(result.stats.nb_bags));
745 values[5] = Int64GetDatum(
static_cast<int64
>(result.stats.max_states));
746 values[6] = Int64GetDatum(
static_cast<int64
>(result.stats.dd_size));
747 unsigned maxenum = 0;
748 for (
unsigned ev : result.stats.n_enumerating)
751 values[7] = Int32GetDatum(
static_cast<int32
>(maxenum));
753 PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
754 }
catch (
const std::exception &e) {
779 auto result = runTrackedFromArgs(fcinfo);
784 *u = uuid_of.at(result.dd.getRoot());
786 }
catch (
const std::exception &e) {
804 auto result = runTrackedFromArgs(fcinfo);
807 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
808 provsql_error(
"ucq_joint_compile_stats: expected composite return type");
809 tupdesc = BlessTupleDesc(tupdesc);
812 bool nulls[8] = {
false,
false,
false,
false,
false,
false,
false,
false};
813 values[0] = Float8GetDatum(result.dd.probabilityEvaluation());
814 values[1] = Int32GetDatum(
static_cast<int32
>(result.stats.joint_treewidth));
815 values[2] = Int32GetDatum(
static_cast<int32
>(result.stats.data_treewidth_lb));
816 values[3] = Int32GetDatum(
static_cast<int32
>(result.stats.circuit_treewidth_lb));
817 values[4] = Int64GetDatum(
static_cast<int64
>(result.stats.nb_bags));
818 values[5] = Int64GetDatum(
static_cast<int64
>(result.stats.max_states));
819 values[6] = Int64GetDatum(
static_cast<int64
>(result.stats.dd_size));
820 unsigned maxenum = 0;
821 for (
unsigned ev : result.stats.n_enumerating)
824 values[7] = Int32GetDatum(
static_cast<int32
>(maxenum));
826 PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
827 }
catch (
const std::exception &e) {
850struct JwAnswerCache {
851 bool declined =
false;
852 std::vector<std::string> keys;
853 std::vector<pg_uuid_t> tokens;
857void jwAnswerCacheDelete(
void *arg)
859 delete reinterpret_cast<JwAnswerCache *
>(arg);
863std::string jwHeadKey(
const std::vector<std::string> &vals)
866 for (
const auto &v : vals) { k += v; k.push_back(
'\x1f'); }
883 const std::vector<unsigned> &head_vars,
884 JwAnswerCache *
cache)
887 Oid argt[1] = { JSONBOID };
888 Datum argv[1] = { descriptor };
889 char argn[1] = {
' ' };
890 const int rc = SPI_execute_with_args(
891 "SELECT * FROM provsql.ucq_joint_gather($1)", 1, argt, argv, argn,
true, 1);
892 if (rc != SPI_OK_SELECT || SPI_processed != 1) {
897 std::vector<std::string> keys;
898 std::vector<pg_uuid_t> tokens;
901 TupleDesc td = SPI_tuptable->tupdesc;
902 HeapTuple row = SPI_tuptable->vals[0];
904 auto intArr = [&](
int col,
int &n) ->
const int32 * {
905 Datum dd = SPI_getbinval(row, td, col, &isnull);
906 if (isnull) { n = 0;
return nullptr; }
907 ArrayType *a = DatumGetArrayTypeP(dd);
908 n = ArrayGetNItems(ARR_NDIM(a), ARR_DIMS(a));
909 return (
const int32 *) ARR_DATA_PTR(a);
911 int n_dnv, n_adisj, n_arel, n_avars, n_aarity, n_frel, n_felems, n_farity;
912 const int32 *dnv = intArr(1, n_dnv);
913 const int32 *adisj = intArr(2, n_adisj);
914 const int32 *arel = intArr(3, n_arel);
915 const int32 *avars = intArr(4, n_avars);
916 const int32 *aarity = intArr(5, n_aarity);
917 const int32 *frel = intArr(6, n_frel);
918 const int32 *felems = intArr(7, n_felems);
919 const int32 *farity = intArr(8, n_farity);
920 Datum dtok = SPI_getbinval(row, td, 9, &isnull);
921 ArrayType *atok = isnull ? nullptr : DatumGetArrayTypeP(dtok);
922 const int n_ftok = atok ? ArrayGetNItems(ARR_NDIM(atok), ARR_DIMS(atok)) : 0;
924 atok ? (
const pg_uuid_t *) ARR_DATA_PTR(atok) :
nullptr;
926 std::vector<std::string> val_by_id;
927 Datum dval = SPI_getbinval(row, td, 10, &isnull);
929 ArrayType *aval = DatumGetArrayTypeP(dval);
930 Datum *elems;
bool *nulls;
int nval;
931 deconstruct_array(aval, TEXTOID, -1,
false,
TYPALIGN_INT,
932 &elems, &nulls, &nval);
933 val_by_id.resize(nval);
934 for (
int i = 0; i < nval; ++i)
935 val_by_id[i] = nulls[i] ? std::string() : TextDatumGetCString(elems[i]);
940 for (
int d = 0; d < n_dnv; ++d)
941 ucq.
disjuncts[d].n_vars =
static_cast<unsigned>(dnv[d]);
943 for (
int i = 0; i < n_adisj; ++i) {
944 const int dd = adisj[i];
945 const int ar = aarity[i];
948 for (
int k = 0; k < ar; ++k)
949 atom.
vars.push_back(
static_cast<unsigned>(avars[voff + k]));
951 ucq.
disjuncts[dd].atoms.push_back(std::move(atom));
954 const auto answers = materializeAnswersSingleDP(
955 ucq, head_vars, frel, n_frel, felems, n_felems, farity, n_farity,
957 keys.reserve(answers.size());
958 tokens.reserve(answers.size());
959 for (
const auto &kv : answers) {
960 std::vector<std::string> txt;
961 txt.reserve(kv.first.size());
962 for (
unsigned long id : kv.first)
963 txt.push_back(
id < val_by_id.size() ? val_by_id[
id] : std::string());
964 keys.push_back(jwHeadKey(txt));
965 tokens.push_back(kv.second);
972 cache->keys = std::move(keys);
973 cache->tokens = std::move(tokens);
984 JwAnswerCache *
cache =
985 reinterpret_cast<JwAnswerCache *
>(fcinfo->flinfo->fn_extra);
987 if (
cache ==
nullptr) {
989 MemoryContext fnctx = fcinfo->flinfo->fn_mcxt;
990 cache =
new JwAnswerCache();
991 MemoryContextCallback *cb = (MemoryContextCallback *)
992 MemoryContextAllocZero(fnctx,
sizeof(MemoryContextCallback));
993 cb->func = jwAnswerCacheDelete;
995 MemoryContextRegisterResetCallback(fnctx, cb);
996 fcinfo->flinfo->fn_extra =
cache;
998 if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) {
999 cache->declined =
true;
1001 std::vector<unsigned> head_vars;
1003 ArrayType *a = PG_GETARG_ARRAYTYPE_P(1);
1004 const int32 *d = (
const int32 *) ARR_DATA_PTR(a);
1005 const int n = ArrayGetNItems(ARR_NDIM(a), ARR_DIMS(a));
1006 for (
int i = 0; i < n; ++i)
1007 head_vars.push_back(
static_cast<unsigned>(d[i]));
1009 const Datum desc = PG_GETARG_DATUM(0);
1014 MemoryContext oldcxt = CurrentMemoryContext;
1015 ResourceOwner oldowner = CurrentResourceOwner;
1016 BeginInternalSubTransaction(NULL);
1020 cache->declined =
true;
1021 ReleaseCurrentSubTransaction();
1022 MemoryContextSwitchTo(oldcxt);
1023 CurrentResourceOwner = oldowner;
1027 MemoryContextSwitchTo(oldcxt);
1028 RollbackAndReleaseCurrentSubTransaction();
1029 MemoryContextSwitchTo(oldcxt);
1030 CurrentResourceOwner = oldowner;
1032 cache->declined =
true;
1033 cache->keys.clear();
1034 cache->tokens.clear();
1041 if (!
cache->declined && !PG_ARGISNULL(2)) {
1042 std::vector<std::string> hv;
1043 ArrayType *a = PG_GETARG_ARRAYTYPE_P(2);
1044 Datum *elems;
bool *nulls;
int n;
1045 deconstruct_array(a, TEXTOID, -1,
false,
TYPALIGN_INT, &elems, &nulls, &n);
1046 for (
int i = 0; i < n; ++i)
1047 hv.push_back(nulls[i] ? std::string() : TextDatumGetCString(elems[i]));
1048 const std::string key = jwHeadKey(hv);
1049 for (std::size_t i = 0; i <
cache->keys.size(); ++i)
1050 if (
cache->keys[i] == key) {
1052 *u =
cache->tokens[i];
1053 PG_RETURN_UUID_P(u);
1058 if (PG_ARGISNULL(3))
1060 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, provsql_route route)
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.
@ PROVSQL_ROUTE_BOUNDED_JW
Joint-width UCQ compiler (src/UCQJointCompiler.h).
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.