Skip to content

Allow nested negation and universal quantification in rules #277

Open
@james-whiteside

Description

@james-whiteside

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).

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions