ProvSQL C/C++ API
Adding support for provenance and uncertainty management to PostgreSQL databases
Loading...
Searching...
No Matches
RvSample.cpp
Go to the documentation of this file.
1/**
2 * @file RvSample.cpp
3 * @brief SQL function `provsql.rv_sample(token, n, prov)`.
4 *
5 * Returns up to @c n samples from the (possibly conditional) scalar
6 * distribution rooted at @c token. When @c prov resolves to
7 * @c gate_one the samples come from the unconditional distribution
8 * (one draw per call to @c monteCarloScalarSamples); when @c prov is
9 * a non-trivial gate the path switches to MC rejection via
10 * @c monteCarloConditionalScalarSamples, with a budget large enough
11 * to deliver @c n accepted draws under the @c acceptance_floor
12 * heuristic.
13 *
14 * Result: @c SETOF @c float8 emitted through the Materialize SRF
15 * pattern (same shape as @c shapley_all_vars). The unconditional
16 * path always returns exactly @c n rows; the conditional path may
17 * return fewer, in which case a @c NOTICE is emitted so the caller
18 * can choose to widen the budget by raising
19 * @c provsql.rv_mc_samples.
20 */
21extern "C" {
22#include "postgres.h"
23#include "fmgr.h"
24#include "funcapi.h"
25#include "miscadmin.h"
26#include "utils/builtins.h"
27#include "utils/uuid.h"
28#include "provsql_utils.h"
29#include "provsql_error.h"
30
31PG_FUNCTION_INFO_V1(rv_sample);
32}
33
34#include "CircuitFromMMap.h"
35#include "Expectation.h"
36#include "GenericCircuit.h"
37#include "MonteCarloSampler.h"
38#include "provsql_utils_cpp.h"
39
40#include <algorithm>
41#include <optional>
42#include <vector>
43
44extern "C" Datum
45rv_sample(PG_FUNCTION_ARGS)
46{
47 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
48
49 MemoryContext per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
50 MemoryContext oldcontext = MemoryContextSwitchTo(per_query_ctx);
51
52 TupleDesc tupdesc = rsinfo->expectedDesc;
53 Tuplestorestate *tupstore = tuplestore_begin_heap(
54 rsinfo->allowedModes & SFRM_Materialize_Random, false, work_mem);
55
56 rsinfo->returnMode = SFRM_Materialize;
57 rsinfo->setResult = tupstore;
58
59 try {
60 pg_uuid_t *token = (pg_uuid_t *) PG_GETARG_POINTER(0);
61 const int32 n_signed = PG_GETARG_INT32(1);
62 pg_uuid_t *prov = (pg_uuid_t *) PG_GETARG_POINTER(2);
63
64 if (n_signed <= 0)
65 provsql_error("rv_sample: n must be positive (got %d)", n_signed);
66 const unsigned n = static_cast<unsigned>(n_signed);
67
68 gate_t root_gate, event_gate;
69 auto gc = getJointCircuit(*token, *prov, root_gate, event_gate);
70
71 /* A stored "X | C" arrives as a conditioned root: peel it to the bare
72 * scalar target and fold the condition into the event so the rest of the
73 * function samples the conditional (truncated) distribution. */
74 std::optional<gate_t> event_opt;
75 if (gc.getGateType(event_gate) != gate_one) event_opt = event_gate;
76 root_gate = provsql::lift_conditioning(gc, root_gate, event_opt);
77 const bool conditional = event_opt.has_value();
78
79 std::vector<double> samples;
80 if (conditional) {
81 const gate_t event = *event_opt;
82 /* Closed-form truncation fast path: when the root is a bare
83 * gate_rv of a supported family (Uniform / Normal / Exponential)
84 * and the event reduces to a single interval on it, we draw
85 * exactly @c n samples directly from the truncated distribution.
86 * 100% acceptance, no NOTICE on tight events like X > 9.5 over
87 * U(0, 10) that the MC rejection path degrades on. Falls
88 * through to the MC rejection path for un-extractable shapes
89 * (Erlang, gate_arith composites, gate_mixture roots…). */
91 gc, root_gate, event, n);
92 if (direct) {
93 samples = std::move(*direct);
94 } else {
95 /* Budget: n / acceptance_floor candidate draws, capped at the
96 * GUC ceiling. acceptance_floor = 0.001 means a 0.1% acceptance
97 * rate still delivers n samples; rates below that yield fewer
98 * samples + a NOTICE. */
99 const unsigned budget = std::min(
100 static_cast<unsigned>(1000u) * n,
102 ? static_cast<unsigned>(provsql_rv_mc_samples) : 1000u * n);
104 gc, root_gate, event, budget);
105 if (cs.accepted.size() > n) cs.accepted.resize(n);
106 if (cs.accepted.size() < n) {
107 ereport(NOTICE,
108 (errmsg("rv_sample: requested %u, returning %zu "
109 "(acceptance rate %zu/%u)",
110 n, cs.accepted.size(),
111 cs.accepted.size(), cs.attempted)));
112 }
113 samples = std::move(cs.accepted);
114 }
115 } else {
116 samples = provsql::monteCarloScalarSamples(gc, root_gate, n);
117 }
118
119 for (double x : samples) {
120 Datum values[1] = { Float8GetDatum(x) };
121 bool nulls[1] = { false };
122 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
123 }
124 } catch (const std::exception &e) {
125 MemoryContextSwitchTo(oldcontext);
126 provsql_error("rv_sample: %s", e.what());
127 } catch (...) {
128 MemoryContextSwitchTo(oldcontext);
129 provsql_error("rv_sample: unknown exception");
130 }
131
132 MemoryContextSwitchTo(oldcontext);
133 PG_RETURN_NULL();
134}
GenericCircuit getJointCircuit(pg_uuid_t root_token, pg_uuid_t event_token, gate_t &root_gate, gate_t &event_gate)
Build a GenericCircuit containing the closures of two roots, with shared subgraphs unified.
Build in-memory circuits from the mmap-backed persistent store.
gate_t
Strongly-typed gate identifier.
Definition Circuit.h:49
Analytical expectation / variance / moment evaluator over RV circuits.
Semiring-agnostic in-memory provenance circuit.
Monte Carlo sampling over a GenericCircuit, RV-aware.
Datum rv_sample(PG_FUNCTION_ARGS)
Definition RvSample.cpp:45
gate_t lift_conditioning(GenericCircuit &gc, gate_t root, std::optional< gate_t > &event_opt)
Lift conditioning out of a scalar arithmetic expression.
ConditionalScalarSamples monteCarloConditionalScalarSamples(const GenericCircuit &gc, gate_t root, gate_t event_root, unsigned samples)
Rejection-sample root conditioned on event_root.
std::vector< double > monteCarloScalarSamples(const GenericCircuit &gc, gate_t root, unsigned samples)
Sample a scalar sub-circuit samples times and return the draws.
std::optional< std::vector< double > > try_truncated_closed_form_sample(const GenericCircuit &gc, gate_t root, gate_t event_root, unsigned n)
Try to draw n exact samples from the conditional distribution of root given event_root via closed-for...
int provsql_rv_mc_samples
Default sample count for analytical-evaluator MC fallbacks; 0 disables fallback (callers raise instea...
Definition provsql.c:96
Uniform error-reporting macros for ProvSQL.
#define provsql_error(fmt,...)
Report a fatal ProvSQL error and abort the current transaction.
Core types, constants, and utilities shared across ProvSQL.
C++ utility functions for UUID manipulation.
UUID structure.