23 double pdf_c = std::numeric_limits<double>::quiet_NaN();
29 const double mu = d.
p1, sigma = d.
p2;
30 if (!(sigma > 0.0))
break;
31 static const double SQRT_2PI = std::sqrt(2.0 * M_PI);
32 const double z = (c - mu) / sigma;
33 pdf_c = std::exp(-0.5 * z * z) / (sigma * SQRT_2PI);
37 const double a = d.
p1, b = d.
p2;
39 pdf_c = (c < a || c > b) ? 0.0 : 1.0 / (b - a);
43 const double lambda = d.
p1;
44 if (!(lambda > 0.0))
break;
45 pdf_c = (c < 0.0) ? 0.0 : lambda * std::exp(-lambda * c);
52 const double s = d.
p1, lambda = d.
p2;
53 if (s < 1.0 || s != std::floor(s) || !(lambda > 0.0))
break;
54 if (c < 0.0) { pdf_c = 0.0;
break; }
55 const unsigned long k =
static_cast<unsigned long>(s);
59 for (
unsigned long i = 2; i < k; ++i) fact *= static_cast<double>(i);
60 pdf_c = std::pow(lambda,
static_cast<double>(k))
61 * std::pow(c,
static_cast<double>(k - 1))
62 * std::exp(-lambda * c)
72 double cdf_c = std::numeric_limits<double>::quiet_NaN();
77 static const double SQRT2 = std::sqrt(2.0);
78 double z = (c - d.
p1) / d.
p2;
79 cdf_c = 0.5 * (1.0 + std::erf(z / SQRT2));
83 if (c <= d.
p1) cdf_c = 0.0;
84 else if (c >= d.
p2) cdf_c = 1.0;
85 else cdf_c = (c - d.
p1) / (d.
p2 - d.
p1);
88 if (c <= 0.0) cdf_c = 0.0;
89 else cdf_c = -std::expm1(-d.
p1 * c);
99 const double s = d.
p1, lambda = d.
p2;
100 if (s < 1.0 || s != std::floor(s))
break;
101 if (c <= 0.0) { cdf_c = 0.0;
break; }
102 const double lc = lambda * c;
105 const unsigned long k =
static_cast<unsigned long>(s);
106 for (
unsigned long n = 1; n < k; ++n) {
107 term *= lc /
static_cast<double>(n);
110 cdf_c = 1.0 - std::exp(-lc) * sum;
126 double cdf_c =
cdfAt(d, c);
127 if (std::isnan(cdf_c))
return cdf_c;
142 return std::numeric_limits<double>::quiet_NaN();
144 return std::numeric_limits<double>::quiet_NaN();
171 diff.p1 = X.p1 - Y.p1;
172 diff.p2 = std::sqrt(X.p2 * X.p2 + Y.p2 * Y.p2);
173 return cdfDecide(diff, op, 0.0);
178double bareValue(
const GenericCircuit &gc,
gate_t g)
181 return std::numeric_limits<double>::quiet_NaN();
183 catch (
const CircuitException &) {
184 return std::numeric_limits<double>::quiet_NaN();
190std::optional<DistributionSpec>
191bareRv(
const GenericCircuit &gc,
gate_t g)
209double categoricalDecide(
const GenericCircuit &gc,
gate_t mix,
212 const auto &wires = gc.
getWires(mix);
214 for (std::size_t i = 1; i < wires.size(); ++i) {
217 catch (
const CircuitException &) {
218 return std::numeric_limits<double>::quiet_NaN();
229 if (hit) p += gc.
getProb(wires[i]);
246double tryAnalyticDecide(
const GenericCircuit &gc,
gate_t cmp_gate)
250 if (!ok)
return std::numeric_limits<double>::quiet_NaN();
252 const auto &wires = gc.
getWires(cmp_gate);
253 if (wires.size() != 2)
return std::numeric_limits<double>::quiet_NaN();
254 gate_t lhs = wires[0], rhs = wires[1];
257 if (
auto specX = bareRv(gc, lhs)) {
258 double c = bareValue(gc, rhs);
259 if (!std::isnan(c))
return cdfDecide(*specX, op, c);
263 if (
auto specX = bareRv(gc, rhs)) {
264 double c = bareValue(gc, lhs);
265 if (!std::isnan(c))
return cdfDecide(*specX, flipCmpOp(op), c);
273 double c = bareValue(gc, rhs);
274 if (!std::isnan(c))
return categoricalDecide(gc, lhs, op, c);
277 double c = bareValue(gc, lhs);
278 if (!std::isnan(c))
return categoricalDecide(gc, rhs, flipCmpOp(op), c);
286 auto specX = bareRv(gc, lhs);
287 auto specY = bareRv(gc, rhs);
288 if (specX && specY &&
291 return normalDiffDecide(*specX, *specY, op);
295 return std::numeric_limits<double>::quiet_NaN();
302 unsigned resolved = 0;
307 std::vector<gate_t> cmps;
308 for (std::size_t i = 0; i < nb; ++i) {
309 auto g =
static_cast<gate_t>(i);
316 double p = tryAnalyticDecide(gc, c);
317 if (!std::isnan(p)) {
321 if (p < 0.0) p = 0.0;
322 if (p > 1.0) p = 1.0;
ComparisonOperator cmpOpFromOid(Oid op_oid, bool &ok)
Map a PostgreSQL comparison-operator OID to a ComparisonOperator.
Typed aggregation value, operator, and aggregator abstractions.
ComparisonOperator
SQL comparison operators used in gate_cmp circuit gates.
@ LE
Less than or equal (<=).
@ GE
Greater than or equal (>=).
Closed-form CDF resolution for trivial gate_cmp shapes.
gate_t
Strongly-typed gate identifier.
Continuous random-variable helpers (distribution parsing, moments).
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.
std::vector< gate_t >::size_type getNbGates() const
Return the total number of gates in the circuit.
In-memory provenance circuit with semiring-generic evaluation.
bool isCategoricalMixture(gate_t g) const
Test whether g is a categorical-form gate_mixture (the explicit provsql.categorical output).
std::string getExtra(gate_t g) const
Return the string extra for gate g.
double getProb(gate_t g) const
Return the probability for gate g.
void resolveCmpToBernoulli(gate_t g, double p)
Replace a gate_cmp by a constant Boolean leaf (gate_one for p == 1, gate_zero for p == 0) or by a Ber...
std::pair< unsigned, unsigned > getInfos(gate_t g) const
Return the integer annotation pair for gate g.
@ Normal
Normal (Gaussian): p1=μ, p2=σ
@ Exponential
Exponential: p1=λ, p2 unused.
@ Uniform
Uniform on [a,b]: p1=a, p2=b.
@ Erlang
Erlang: p1=k (positive integer), p2=λ.
double parseDoubleStrict(const std::string &s)
Strictly parse s as a double.
double pdfAt(const DistributionSpec &d, double c)
Closed-form probability density for a basic distribution.
std::optional< DistributionSpec > parse_distribution_spec(const std::string &s)
Parse the on-disk text encoding of a gate_rv distribution.
double cdfAt(const DistributionSpec &d, double c)
Closed-form CDF for a basic continuous distribution.
unsigned runAnalyticEvaluator(GenericCircuit &gc)
Run the closed-form CDF resolution pass over gc.
Core types, constants, and utilities shared across ProvSQL.
@ gate_rv
Continuous random-variable leaf (extra encodes distribution).
Parsed distribution spec (kind + up to two parameters).
double p2
Second parameter (σ or b; unused for Exponential).
double p1
First parameter (μ, a, or λ).