Description
Problem to Solve
TypeQL does not currently support nested negation (not { not { <pattern> }; };
) in rule conditions. This makes some logical expressions impossible to construct. Taking the following rule:
rule group-maximisation-violation-detection:
when {
$g1 isa user-group;
$g2 isa user-group;
not {
(permitted-subject: $g1, permitted-access: $a) isa permission;
not { (subject: $g2, access: $a) isa permission; };
not { (group: $g1, member: $s) isa group-membership; };
(group: $g2, member: $s) isa group-membership;
} ;
} then {
(group: $g1, group: $g2) isa group-maximisation-violation;
};
and applying De Morgan's laws to cancel out the nested negation gives:
rule group-maximisation-violation-detection:
when {
$g1 isa user-group;
$g2 isa user-group;
{
not { (permitted-subject: $g1, permitted-access: $a) isa permission; };
} or {
(subject: $g2, access: $a) isa permission;
} or {
(group: $g1, member: $s) isa group-membership;
} or {
not { (group: $g2, member: $s) isa group-membership; };
};
} then {
(group: $g1, group: $g2) isa group-maximisation-violation;
};
which does not achieve the same result. The second version of the rule will insert a group-maximisation-violation
relation between every possible pair of groups in the database as long as at least one $a
or $s
exists, which is not the case for the first one. This is because applying De Morgan's laws requires proper treatment of qualifiers. Stating the first version of the rule mathematically gives:
g : user-group
a : access
s : subject
p : permission
m : group-membership
v : group-maximisation-violation
∃(g1, g2) . ( ¬∃(a, s) . ( p(g1, a) ∧ ¬p(g2, a) ∧ ¬m(g2, s) ∧ m(g1, s) ) ) → v(g1, g2)
Now applying De Morgan's laws gives:
∃(g1, g2) . ( ∀(a, s) . ( ¬p(g1, a) ∨ p(g2, a) ∨ m(g2, s) ∨ ¬m(g1, s) ) ) → v(g1, g2)
The existential qualifier ∃
is implicit in TypeQL (elegantly allowing the implicit binding of $a
and $s
), but as there is no universal quantifier ∀
, the second version of the rule cannot be constructed. This means that, as nested negations are currently not permitted, it is impossible to create this logical expression in a single rule's conditions.
As a minimum to solve this issue, nested negations would need to be permitted, but it would be very powerful to introduce notation for universal quantification. By De Morgan's laws, universal quantification is never necessary as it can always be replaced with nested negation. This is the approach that Prolog uses, and nested negation is an encouraged design pattern in the language. While the addition of a universal quantifier would not increase TypeDB's expressivity, it would significantly improve readability and reduce rule complexity.
Current Workaround
Use multiple rules with one level of negation per rule.
Proposed Solution
Permit nested negation (short-term), and introduce a universal quantifier (long-term).