ProvSQL C/C++ API
Adding support for provenance and uncertainty management to PostgreSQL databases
Loading...
Searching...
No Matches
Semiring.h
Go to the documentation of this file.
1/**
2 * @file semiring/Semiring.h
3 * @brief Abstract semiring interface for provenance evaluation.
4 *
5 * ProvSQL evaluates provenance circuits over arbitrary (m-)semirings.
6 * This header defines the abstract base class @c semiring::Semiring<V>
7 * that every concrete semiring must implement.
8 *
9 * A **semiring** @f$(S, \oplus, \otimes, \mathbb{0}, \mathbb{1})@f$
10 * consists of:
11 * - A carrier set @f$S@f$ (the @c value_type).
12 * - An additive operation @f$\oplus@f$ with identity @f$\mathbb{0}@f$.
13 * - A multiplicative operation @f$\otimes@f$ with identity @f$\mathbb{1}@f$.
14 *
15 * An **m-semiring** additionally provides:
16 * - A monus operation @f$\ominus@f$ used for set-difference queries.
17 * - A @f$\delta@f$ operator.
18 *
19 * Optional operations -- comparison, semimodule scalar multiplication,
20 * aggregation, value literals, and the measure-carrier gates
21 * (random-variable leaves, scalar arithmetic, mixtures, guarded
22 * selection, observations, conditioning) -- are provided by subclasses
23 * that support them; the base class throws @c SemiringException for all
24 * of these. Most carry no algebraic meaning in a general semiring and
25 * are overridden only by @c Formula, whose carrier is a symbolic
26 * rendering of the circuit rather than a semantic value.
27 *
28 * Concrete implementations live in the same @c semiring/ directory:
29 * @c Boolean.h, @c Counting.h, @c Formula.h, @c Why.h, @c BoolExpr.h.
30 *
31 * @see https://provsql.org/lean-docs/Provenance/SemiringWithMonus.html
32 * Lean 4 formalization of the @c SemiringWithMonus typeclass and
33 * proofs of the key monus identities (@c monus_smallest,
34 * @c monus_self, @c zero_monus, @c monus_add, @c add_monus,
35 * @c idempotent_iff_add_monus).
36 */
37#ifndef SEMIRING_H
38#define SEMIRING_H
39
40#include <vector>
41#include <string>
42
43#include "../Aggregation.h"
44
45namespace semiring {
46
47/**
48 * @brief Exception thrown when a semiring operation is not supported.
49 *
50 * Raised by the default implementations of optional operations
51 * (@c cmp, @c semimod, @c agg, @c value) when a subclass does not
52 * override them.
53 */
54class SemiringException : public std::exception
55{
56std::string message; ///< Human-readable description of the error
57
58public:
59/**
60 * @brief Construct with a descriptive error message.
61 * @param m Error message.
62 */
63SemiringException(const std::string &m) : message(m) {
64}
65/**
66 * @brief Return the error message as a C-string.
67 * @return Null-terminated error description.
68 */
69virtual char const * what() const noexcept {
70 return message.c_str();
71}
72};
73
74/**
75 * @brief Abstract base class for (m-)semirings.
76 *
77 * @tparam V The carrier type (e.g. @c bool, @c unsigned, @c std::string).
78 *
79 * ### Required operations
80 * All pure-virtual methods must be implemented by concrete subclasses.
81 *
82 * ### Optional operations
83 * @c cmp(), @c semimod(), @c agg(), and @c value() have default
84 * implementations that throw @c SemiringException. Override them in
85 * subclasses that support these circuit gate types.
86 *
87 * ### Absorptive semirings
88 * A semiring is *absorptive* (i.e.,
89 * @f$\mathbb{1} \oplus a = \mathbb{1}@f$ for all @f$a@f$) iff
90 * @c absorptive() returns @c true. Absorptivity implies idempotency
91 * (@f$a \oplus a = a@f$), which lets the circuit evaluator and the
92 * HAVING-semantics machinery deduplicate operands and short-circuit
93 * over the multiplicative identity.
94 */
95template<typename V>
97{
98public:
99/** @brief The carrier type of this semiring. */
100typedef V value_type;
101
102/**
103 * @brief Return the additive identity @f$\mathbb{0}@f$.
104 * @return The zero element of the semiring.
105 */
106virtual value_type zero() const = 0;
107
108/**
109 * @brief Return the multiplicative identity @f$\mathbb{1}@f$.
110 * @return The one element of the semiring.
111 */
112virtual value_type one() const = 0;
113
114/**
115 * @brief Apply the additive operation to a list of values.
116 *
117 * @param v Ordered list of operands (empty list should return @c zero()).
118 * @return @f$v_0 \oplus v_1 \oplus \cdots@f$.
119 */
120virtual value_type plus(const std::vector<value_type> &v) const = 0;
121
122/**
123 * @brief Apply the multiplicative operation to a list of values.
124 *
125 * @param v Ordered list of operands (empty list should return @c one()).
126 * @return @f$v_0 \otimes v_1 \otimes \cdots@f$.
127 */
128virtual value_type times(const std::vector<value_type> &v) const = 0;
129
130/**
131 * @brief Apply the monus (m-semiring difference) operation.
132 *
133 * @param x Minuend.
134 * @param y Subtrahend.
135 * @return @f$x \ominus y@f$.
136 */
137virtual value_type monus(value_type x, value_type y) const = 0;
138
139/**
140 * @brief Apply the @f$\delta@f$ operator.
141 *
142 * @param x Input value.
143 * @return @f$\delta(x)@f$.
144 */
145virtual value_type delta(value_type x) const = 0;
146
147/**
148 * @brief Evaluate a comparison gate.
149 *
150 * @param s1 Left operand.
151 * @param op Comparison operator.
152 * @param s2 Right operand.
153 * @return Result of the comparison in this semiring.
154 * @throws SemiringException if not overridden.
155 */
157 throw SemiringException("This semiring does not support cmp gates.");
158}
159
160/**
161 * @brief Apply a semimodule scalar multiplication.
162 *
163 * @param x Provenance value.
164 * @param s Scalar value.
165 * @return @f$x * s@f$ in the semimodule.
166 * @throws SemiringException if not overridden.
167 */
169 throw SemiringException("This semiring does not support semimod gates.");
170}
171
172/**
173 * @brief Evaluate an aggregation gate.
174 *
175 * @param op The aggregation function (COUNT, SUM, MIN…).
176 * @param s List of child semiring values to aggregate.
177 * @return The aggregated value.
178 * @throws SemiringException if not overridden.
179 */
180virtual value_type agg(AggregationOperator op, const std::vector<value_type> &s) {
181 throw SemiringException("This semiring does not support agg gates.");
182}
183
184/**
185 * @brief Interpret a literal string as a semiring value.
186 *
187 * Used for @c gate_value gates whose payload is a string.
188 *
189 * @param s Literal string.
190 * @return The corresponding semiring value.
191 * @throws SemiringException if not overridden.
192 */
193virtual value_type value(const std::string &s) const {
194 throw SemiringException("This semiring does not support value gates.");
195}
196
197/**
198 * @brief Value of a variable leaf (@c gate_input / @c gate_mulinput)
199 * that the provenance mapping does not name.
200 *
201 * The absent-mapping convention: such a leaf contributes no provenance,
202 * i.e. the multiplicative identity, which is what every proper semiring
203 * wants and what this default returns. A semiring that *renders* the
204 * circuit rather than evaluating it overrides this to identify the leaf
205 * instead -- @f$\mathbb{1}@f$ would not merely be anonymous there, it
206 * would be absorbed by the enclosing @c times and take the structure
207 * with it. @c BooleanCircuit::toString does the same for the
208 * Boolean-expression rendering (its @c x@<id@> fallback).
209 *
210 * @param uuid The leaf gate's UUID, in canonical text form.
211 */
212virtual value_type unmapped_input(const std::string &uuid) const {
213 return one();
214}
215
216/**
217 * @brief Evaluate a continuous random-variable leaf (@c gate_rv).
218 *
219 * @param spec The gate's distribution encoding (@c "normal:2.5,0.5"),
220 * where a parameter written @c "$i" is wired rather than
221 * literal (a latent / compound leaf).
222 * @param params The values of the gate's wires, indexed as the @c "$i"
223 * references; empty for an all-literal leaf.
224 * @return The leaf's value in this semiring.
225 * @throws SemiringException if not overridden.
226 */
227virtual value_type rv(const std::string &spec,
228 const std::vector<value_type> &params) const {
229 throw SemiringException(
230 "This semiring does not support rv gates: a continuous "
231 "distribution is not a semiring value. Query a "
232 "random-variable token through the measure surface "
233 "(expected / variance / quantile / support / sample), or use "
234 "the formula pseudo-semiring for a symbolic rendering.");
235}
236
237/**
238 * @brief Evaluate an arithmetic gate over scalar children (@c gate_arith).
239 *
240 * @param op The arithmetic operation.
241 * @param children The values of the gate's wires (for @c PERCENTILE,
242 * interleaved @c [indicator, value] pairs).
243 * @param extra The gate's payload (the fraction for @c PERCENTILE,
244 * empty otherwise).
245 * @return The result of the operation in this semiring.
246 * @throws SemiringException if not overridden.
247 */
249 const std::vector<value_type> &children,
250 const std::string &extra) const {
251 throw SemiringException(
252 "This semiring does not support arith gates: arithmetic over "
253 "scalar (random-variable) children is not a semiring "
254 "operation. Query such a token through the measure surface "
255 "(expected / variance / quantile / support / sample), or use "
256 "the formula pseudo-semiring for a symbolic rendering.");
257}
258
259/**
260 * @brief Evaluate a Bernoulli mixture (@c gate_mixture, three wires).
261 *
262 * @param p The Bernoulli event's value.
263 * @param x The value taken when the event holds.
264 * @param y The value taken otherwise.
265 * @throws SemiringException if not overridden.
266 */
268 throw SemiringException(
269 "This semiring does not support mixture gates: a probabilistic "
270 "mixture is not a semiring operation. Query such a token "
271 "through the measure surface (expected / variance / quantile / "
272 "support / sample), or use the formula pseudo-semiring for a "
273 "symbolic rendering.");
274}
275
276/**
277 * @brief Evaluate a categorical mixture (@c gate_mixture over
278 * @c gate_mulinput outcomes).
279 *
280 * @param key The value of the mixture's key (its @c gate_input wire).
281 * @param probs Probability of each outcome.
282 * @param outcomes Textual payload of each outcome, parallel to @p probs.
283 * @throws SemiringException if not overridden.
284 */
286 const std::vector<double> &probs,
287 const std::vector<std::string> &outcomes) const {
288 throw SemiringException(
289 "This semiring does not support categorical mixture gates: a "
290 "distribution over outcomes is not a semiring value. Query "
291 "such a token through the measure surface (expected / "
292 "variance / quantile / support / sample), or use the formula "
293 "pseudo-semiring for a symbolic rendering.");
294}
295
296/**
297 * @brief Evaluate a guarded selection (@c gate_case).
298 *
299 * @param children The gate's wires, @c [guard_1, value_1, …,
300 * guard_k, value_k, default] (odd length), with
301 * first-match semantics.
302 * @throws SemiringException if not overridden.
303 */
304virtual value_type guarded_case(const std::vector<value_type> &children) const {
305 throw SemiringException(
306 "The requested semiring does not support a CASE / guarded "
307 "selection over random variables (gate_case): it is evaluable "
308 "only through the random-variable / measure surface "
309 "(expected / variance / support / probability / sample).");
310}
311
312/**
313 * @brief Evaluate a latent-variable observation (@c gate_observe).
314 *
315 * @param child The observed leaf's value.
316 * @param datum The observed value, as text.
317 * @throws SemiringException if not overridden.
318 */
319virtual value_type observe(value_type child, const std::string &datum) const {
320 throw SemiringException(
321 "This semiring does not support observe gates: the density "
322 "factor of a likelihood-weighting observation is not a "
323 "semiring value. Such a token is evaluated by the "
324 "importance-sampling surface, or rendered symbolically by the "
325 "formula pseudo-semiring.");
326}
327
328/**
329 * @brief Evaluate a conditioning marker (@c gate_conditioned).
330 *
331 * @param children The gate's wires: @c [target, evidence] for the
332 * value-level (random-variable) form, @c [target,
333 * evidence, joint] for the Boolean-event one, where
334 * @c joint is the materialised @c times(target, evidence).
335 * @throws SemiringException if not overridden.
336 */
337virtual value_type conditioned(const std::vector<value_type> &children) const {
338 throw SemiringException(
339 "The requested semiring does not support conditioning: "
340 "P(·|C) = P(·∧C)/P(C) needs a normalising division "
341 "no general semiring provides. A conditioned token is "
342 "evaluable only in the measure interpretation "
343 "(probability_evaluate, or the random-variable / agg_token "
344 "distribution evaluators).");
345}
346
347virtual ~Semiring() = default;
348
349/**
350 * @brief Return @c true if this semiring is absorptive
351 * (@f$\mathbb{1} \oplus a = \mathbb{1}@f$ for all @f$a@f$).
352 *
353 * When @c true, the circuit evaluator and HAVING-semantics machinery
354 * may exploit the resulting idempotency (@f$a \oplus a = a@f$, implied
355 * by absorptivity) to deduplicate children of @c plus gates and to
356 * short-circuit over the multiplicative identity.
357 *
358 * @return @c false by default; override to return @c true.
359 */
360virtual bool absorptive() const {
361 return false;
362}
363
364/**
365 * @brief Return @c true if a semiring homomorphism @c BoolFunc(X)
366 * →+* @c S exists, so the safe-query (Boolean-rewrite)
367 * optimisation produces circuits that are semantically faithful
368 * when evaluated under this semiring.
369 *
370 * The compiled-semiring dispatcher consults this predicate before
371 * evaluating a circuit whose root gate carries
372 * @c PROVSQL_ROOT_TAG_BOOLEAN_REWRITE. Returning @c false on a tagged
373 * circuit raises @c CircuitException.
374 *
375 * Defaults to @c false: a new semiring whose author has not yet
376 * verified the homomorphism is fail-closed by construction.
377 * Subclasses with a verified homomorphism (currently @c Boolean,
378 * @c BoolExpr, @c Formula, and @c IntervalUnion) override to return
379 * @c true. The justification (Lean-proof reference) belongs in a
380 * comment next to each override; see the @c src/semiring/ headers.
381 */
382virtual bool compatibleWithBooleanRewrite() const {
383 return false;
384}
385
386/**
387 * @brief Whether this semiring builds *certified* exclusive
388 * enumerations (see the three hooks below).
389 *
390 * The HAVING possible-worlds machinery (@c provsql_having) enumerates,
391 * for a comparison over a group aggregate, the complete valuations of
392 * the group's contributors that satisfy the predicate. Those
393 * disjuncts partition the worlds -- the OR is *deterministic* and each
394 * world term an AND of literals over distinct contributors,
395 * *decomposable* -- i.e., the enumeration is a d-DNNF by construction.
396 * A circuit-building semiring can persist that knowledge as the d-DNNF
397 * certificate (the same mark the bounded-treewidth reachability route
398 * emits), letting the linear certificate-aware evaluators handle the
399 * result; scalar semirings have nothing to mark.
400 *
401 * @return @c false by default (the hooks below then go unused and the
402 * default constructions are used).
403 */
404virtual bool certifying() const {
405 return false;
406}
407
408/**
409 * @brief Whether @p v is an independent literal for certification
410 * purposes: a base Bernoulli variable (or a constant), so that
411 * distinct literals have disjoint supports and an AND over them
412 * is decomposable.
413 *
414 * Only consulted when @c certifying() is @c true.
415 *
416 * @return @c false by default.
417 */
418virtual bool independent_literal(const value_type &) const {
419 return false;
420}
421
422/**
423 * @brief Build one complete world term: the conjunction of the
424 * @p present literals and the *negations* of the @p missing
425 * literals, certified decomposable.
426 *
427 * Only called when @c certifying() is @c true; the default throws.
428 */
430 const std::vector<value_type> &,
431 const std::vector<value_type> &) const {
432 throw SemiringException("This semiring does not certify enumerations.");
433}
434
435/**
436 * @brief Build the disjunction of pairwise-exclusive @p disjuncts,
437 * certified deterministic.
438 *
439 * Only called when @c certifying() is @c true; the default throws.
440 */
442 const std::vector<value_type> &) const {
443 throw SemiringException("This semiring does not certify enumerations.");
444}
445};
446
447
448}
449
450#endif /* SEMIRING_H */
Typed aggregation value, operator, and aggregator abstractions.
AggregationOperator
SQL aggregation functions tracked by ProvSQL.
Definition Aggregation.h:51
ComparisonOperator
SQL comparison operators used in gate_cmp circuit gates.
Definition Aggregation.h:39
ArithmeticOperator
Arithmetic operations carried by gate_arith circuit gates.
Definition Aggregation.h:74
Exception thrown when a semiring operation is not supported.
Definition Semiring.h:55
std::string message
Human-readable description of the error.
Definition Semiring.h:56
virtual char const * what() const noexcept
Return the error message as a C-string.
Definition Semiring.h:69
SemiringException(const std::string &m)
Construct with a descriptive error message.
Definition Semiring.h:63
Abstract base class for (m-)semirings.
Definition Semiring.h:97
V value_type
The carrier type of this semiring.
Definition Semiring.h:100
virtual value_type semimod(value_type x, value_type s) const
Apply a semimodule scalar multiplication.
Definition Semiring.h:168
virtual value_type plus(const std::vector< value_type > &v) const =0
Apply the additive operation to a list of values.
virtual value_type mixture(value_type p, value_type x, value_type y) const
Evaluate a Bernoulli mixture (gate_mixture, three wires).
Definition Semiring.h:267
virtual bool absorptive() const
Return true if this semiring is absorptive ( for all ).
Definition Semiring.h:360
virtual bool certifying() const
Whether this semiring builds certified exclusive enumerations (see the three hooks below).
Definition Semiring.h:404
virtual ~Semiring()=default
virtual bool compatibleWithBooleanRewrite() const
Return true if a semiring homomorphism BoolFunc(X) →+* S exists, so the safe-query (Boolean-rewrite) ...
Definition Semiring.h:382
virtual value_type zero() const =0
Return the additive identity .
virtual value_type guarded_case(const std::vector< value_type > &children) const
Evaluate a guarded selection (gate_case).
Definition Semiring.h:304
virtual value_type cmp(value_type s1, ComparisonOperator op, value_type s2) const
Evaluate a comparison gate.
Definition Semiring.h:156
virtual value_type agg(AggregationOperator op, const std::vector< value_type > &s)
Evaluate an aggregation gate.
Definition Semiring.h:180
virtual value_type conditioned(const std::vector< value_type > &children) const
Evaluate a conditioning marker (gate_conditioned).
Definition Semiring.h:337
virtual value_type arith(ArithmeticOperator op, const std::vector< value_type > &children, const std::string &extra) const
Evaluate an arithmetic gate over scalar children (gate_arith).
Definition Semiring.h:248
virtual value_type certified_world_term(const std::vector< value_type > &, const std::vector< value_type > &) const
Build one complete world term: the conjunction of the present literals and the negations of the missi...
Definition Semiring.h:429
virtual value_type unmapped_input(const std::string &uuid) const
Value of a variable leaf (gate_input / gate_mulinput) that the provenance mapping does not name.
Definition Semiring.h:212
virtual value_type one() const =0
Return the multiplicative identity .
virtual value_type monus(value_type x, value_type y) const =0
Apply the monus (m-semiring difference) operation.
virtual value_type rv(const std::string &spec, const std::vector< value_type > &params) const
Evaluate a continuous random-variable leaf (gate_rv).
Definition Semiring.h:227
virtual value_type certified_exclusive_plus(const std::vector< value_type > &) const
Build the disjunction of pairwise-exclusive disjuncts, certified deterministic.
Definition Semiring.h:441
virtual value_type delta(value_type x) const =0
Apply the operator.
virtual value_type times(const std::vector< value_type > &v) const =0
Apply the multiplicative operation to a list of values.
virtual value_type observe(value_type child, const std::string &datum) const
Evaluate a latent-variable observation (gate_observe).
Definition Semiring.h:319
virtual value_type categorical(value_type key, const std::vector< double > &probs, const std::vector< std::string > &outcomes) const
Evaluate a categorical mixture (gate_mixture over gate_mulinput outcomes).
Definition Semiring.h:285
virtual bool independent_literal(const value_type &) const
Whether v is an independent literal for certification purposes: a base Bernoulli variable (or a const...
Definition Semiring.h:418
virtual value_type value(const std::string &s) const
Interpret a literal string as a semiring value.
Definition Semiring.h:193