ProvSQL C/C++ API
Adding support for provenance and uncertainty management to PostgreSQL databases
Loading...
Searching...
No Matches
MinMax.h
Go to the documentation of this file.
1/**
2 * @file semiring/MinMax.h
3 * @brief Min-max and max-min m-semirings over PostgreSQL @c enum types.
4 *
5 * The min-max m-semiring associates each gate with an enum value drawn
6 * from a bounded linear order (the @c pg_enum.enumsortorder of the
7 * carrier enum type). Two instantiations are provided through a single
8 * class:
9 *
10 * - @b MinMax (@c reverse @c = @c false): @f$\oplus = \min@f$,
11 * @f$\otimes = \max@f$, @f$\mathbb{0} = \top@f$, @f$\mathbb{1} =
12 * \bot@f$. This is the security / access-control shape: alternative
13 * derivations combine to the *least* sensitive label, and joins
14 * combine to the *most* sensitive label.
15 *
16 * - @b MaxMin (@c reverse @c = @c true): @f$\oplus = \max@f$,
17 * @f$\otimes = \min@f$, @f$\mathbb{0} = \bot@f$, @f$\mathbb{1} =
18 * \top@f$. This is the fuzzy / availability / trust-level shape:
19 * alternatives combine to the *most* permissive label, and joins
20 * combine to the *strictest* label.
21 *
22 * Operations (described for @c MinMax; @c MaxMin is symmetric):
23 * - @c zero() → @f$\top@f$ (largest enum value by sortorder)
24 * - @c one() → @f$\bot@f$ (smallest enum value by sortorder)
25 * - @c plus() → enum-min over operands (empty list → @c zero())
26 * - @c times() → enum-max over operands (empty list → @c one())
27 * - @c monus() → @f$\mathbb{0}@f$ if @f$x \le_S y@f$, else @f$x@f$,
28 * where @f$\le_S@f$ is the semiring order
29 * - @c delta() → identity (preserves the lattice value of the support so
30 * that aggregated groups carry the meaningful classification
31 * of contributing rows rather than a flattened @c one())
32 *
33 * Absorptivity: `absorptive()` returns `true`. With inputs in the
34 * bounded order, @f$\mathbb{1} \oplus a = a \oplus \mathbb{1} =
35 * \mathbb{1}@f$ in both instantiations.
36 *
37 * @note Bottom and top are looked up once in the constructor from
38 * @c pg_enum.enumsortorder via the @c ENUMTYPOIDNAME syscache. Element
39 * comparison goes through @c F_ENUM_CMP via @c OidFunctionCall2, which
40 * handles the typecache lookup internally.
41 *
42 * @see https://provsql.org/lean-docs/Provenance/Semirings/MinMax.html
43 * Lean 4 verified instance: @c instSemiringWithMonusMinMax
44 * (and @c MaxMin = @c MinMax(OrderDual)).
45 */
46#ifndef MIN_MAX_H
47#define MIN_MAX_H
48
49extern "C" {
50#include "fmgr.h"
51#include "catalog/pg_enum.h"
52#include "utils/catcache.h"
53#include "utils/fmgroids.h"
54#include "utils/syscache.h"
55#include "utils/lsyscache.h"
56#include "access/htup_details.h"
57}
58
59#include <vector>
60#include <stdexcept>
61
62#include "Semiring.h"
63
64namespace semiring {
65/**
66 * @brief Min-max / max-min m-semiring with @c Datum carrier over a
67 * PostgreSQL enum type.
68 *
69 * A single class covers both the @b MinMax (@c reverse @c = @c false,
70 * the security shape) and the @b MaxMin (@c reverse @c = @c true, the
71 * fuzzy / trust shape) instantiations: the two are related by order
72 * reversal on the same carrier. Bottom and top of the carrier enum are
73 * looked up once in the constructor and cached as @c bottom_datum /
74 * @c top_datum.
75 */
76class MinMax : public semiring::Semiring<Datum>
77{
84
85static int enum_cmp_datum(Datum a, Datum b) {
86 return DatumGetInt32(OidFunctionCall2(F_ENUM_CMP, a, b));
87}
88
89public:
90explicit MinMax(Oid enum_type_oid, bool reverse_)
91 : enum_oid(enum_type_oid), reverse(reverse_)
92{
93 CatCList *list = SearchSysCacheList1(ENUMTYPOIDNAME, ObjectIdGetDatum(enum_oid));
94 if(list->n_members == 0) {
95 ReleaseCatCacheList(list);
96 throw std::runtime_error("MinMax: enum type has no members");
97 }
98 Oid b_oid = InvalidOid, t_oid = InvalidOid;
99 float4 b_order = 0, t_order = 0;
100 for(int i = 0; i < list->n_members; ++i) {
101 HeapTuple tup = &list->members[i]->tuple;
102 Form_pg_enum en = (Form_pg_enum) GETSTRUCT(tup);
103#if PG_VERSION_NUM >= 120000
104 Oid label_oid = en->oid;
105#else
106 Oid label_oid = HeapTupleGetOid(tup);
107#endif
108 if(i == 0 || en->enumsortorder < b_order) {
109 b_order = en->enumsortorder;
110 b_oid = label_oid;
111 }
112 if(i == 0 || en->enumsortorder > t_order) {
113 t_order = en->enumsortorder;
114 t_oid = label_oid;
115 }
116 }
117 ReleaseCatCacheList(list);
118
119 bottom_datum = ObjectIdGetDatum(b_oid);
120 top_datum = ObjectIdGetDatum(t_oid);
121
122 getTypeInputInfo(enum_oid, &in_func, &typioparam);
123}
124
125virtual value_type zero() const override {
126 return reverse ? bottom_datum : top_datum;
127}
128virtual value_type one() const override {
129 return reverse ? top_datum : bottom_datum;
130}
131virtual value_type plus(const std::vector<value_type> &v) const override {
132 if(v.empty()) return zero();
133 Datum r = v[0];
134 for(size_t i = 1; i < v.size(); ++i) {
135 int c = enum_cmp_datum(v[i], r);
136 if((!reverse && c < 0) || (reverse && c > 0))
137 r = v[i];
138 }
139 return r;
140}
141virtual value_type times(const std::vector<value_type> &v) const override {
142 if(v.empty()) return one();
143 Datum r = v[0];
144 for(size_t i = 1; i < v.size(); ++i) {
145 int c = enum_cmp_datum(v[i], r);
146 if((!reverse && c > 0) || (reverse && c < 0))
147 r = v[i];
148 }
149 return r;
150}
151virtual value_type monus(value_type x, value_type y) const override
152{
153 // x ⊖ y = 0 if x ≤_S y, else x. The semiring order ≤_S satisfies
154 // x ≤_S y iff x ⊕ y = y. For MinMax (⊕ = enum-min), this is
155 // x ≥ y in the enum order; for MaxMin (⊕ = enum-max), it is
156 // x ≤ y in the enum order.
157 int c = enum_cmp_datum(x, y);
158 bool x_le_S_y = reverse ? (c <= 0) : (c >= 0);
159 return x_le_S_y ? zero() : x;
160}
161virtual value_type delta(value_type x) const override
162{
163 return x;
164}
165virtual bool absorptive() const override {
166 return true;
167}
168/**
169 * @brief No semiring homomorphism @c BoolFunc(Y) →+* MinMax exists
170 * (the enum-min / enum-max structure cannot model the
171 * Boolean-functions semiring), so the safe-query Boolean
172 * rewrite is unsound under MinMax / MaxMin. Inherits the
173 * @c false default from @c Semiring; this override exists for
174 * documentation.
175 *
176 * Lean: @c Provenance.Semirings.TVL.no_hom_from_BoolFunc
177 * (provenance-lean/Provenance/Semirings/MinMax.lean).
178 */
179virtual bool compatibleWithBooleanRewrite() const override {
180 return false;
181}
182
183/**
184 * @brief Parse an enum text literal to a Datum.
185 *
186 * Used by @c pec_anyenum() to build the input mapping; exposed here so
187 * the parser can share the cached @c in_func / @c typioparam.
188 */
189Datum parse_leaf(const char *str) const {
190 return OidInputFunctionCall(in_func, const_cast<char *>(str), typioparam, -1);
191}
192
193};
194}
195
196#endif /* MIN_MAX_H */
Abstract semiring interface for provenance evaluation.
virtual value_type plus(const std::vector< value_type > &v) const override
Apply the additive operation to a list of values.
Definition MinMax.h:131
Datum top_datum
Definition MinMax.h:81
virtual value_type delta(value_type x) const override
Apply the operator.
Definition MinMax.h:161
virtual value_type monus(value_type x, value_type y) const override
Apply the monus (m-semiring difference) operation.
Definition MinMax.h:151
virtual bool absorptive() const override
Return true if this semiring is absorptive ( for all ).
Definition MinMax.h:165
virtual value_type one() const override
Return the multiplicative identity .
Definition MinMax.h:128
Datum bottom_datum
Definition MinMax.h:80
MinMax(Oid enum_type_oid, bool reverse_)
Definition MinMax.h:90
virtual value_type times(const std::vector< value_type > &v) const override
Apply the multiplicative operation to a list of values.
Definition MinMax.h:141
static int enum_cmp_datum(Datum a, Datum b)
Definition MinMax.h:85
virtual value_type zero() const override
Return the additive identity .
Definition MinMax.h:125
Datum parse_leaf(const char *str) const
Parse an enum text literal to a Datum.
Definition MinMax.h:189
virtual bool compatibleWithBooleanRewrite() const override
No semiring homomorphism BoolFunc(Y) →+* MinMax exists (the enum-min / enum-max structure cannot mode...
Definition MinMax.h:179
Abstract base class for (m-)semirings.
Definition Semiring.h:93