// Souffle - A Datalog Compiler
// Copyright (c) 2020, The Souffle Developers. All rights reserved
// Licensed under the Universal Permissive License v 1.0 as shown at:
// - https://opensource.org/licenses/UPL
// - <souffle root>/licenses/SOUFFLE-UPL.txt

// Tests magic-set where poslabelling is necessary to preserve stratification,
// and neglabelling is not enough.

// Reasoning:
// Suppose we neglabel, and then magic-set directly on the output. Then:
//  * D negatively-depends on neglabel[C] from its sole rule
//  * neglabel[C] depends on A from its unpositively-labelled rule
//  * A depends on magic[A] by definition
//  * magic[A] depends on D from the query rule
// We therefore have a negative cycle:
//      D -> neglabel[C] -> A -> magic[A] -> D
// Positive labelling copies out dependent strata to prevent this

.pragma "magic-transform" "*"

// Stratum 0 - Base Relations
.decl BaseOne(X:number)
.decl BaseTwo(X:number)
.input BaseOne, BaseTwo

// Stratum 1 [depends on: 0]
.decl A(X:number)
.decl B(X:number)
A(X) :- BaseOne(X).
A(X) :- BaseOne(X), B(X).
B(X) :- BaseTwo(X), A(X).

// Stratum 2 [depends on: 0,1]
.decl C(X:number)
C(X) :- BaseTwo(X), A(X), B(X), X != 1.

// Stratum 3 [depends on: 0,1]
.decl R(X:number)
R(X) :- BaseTwo(X), A(X), B(X), X != 0.

// Stratum 4 [depends on: 0,1,2,3]
.decl D(X:number)
D(X) :- BaseOne(X), A(X), !C(X), !R(X).

// Stratum 4 - Query [depends on: 0,1,4]
.decl Query(X:number)
.output Query
Query(X) :- BaseOne(X), D(X), A(X).
