// Souffle - A Datalog Compiler
// Copyright (c) 2023, 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


.type Z = Cst{n:number} | Inf{} | MinusInf{}
.type Interval = Bottom{} | I{lb:Z, ub:Z}

.functor lub(a:Interval, b:Interval):Interval stateful
.functor glb(a:Interval, b:Interval):Interval stateful
.functor incr(i:Interval, x:number):Interval stateful

.lattice Interval<> {
    Bottom -> $Bottom(),
    Top    -> $I($MinusInf(), $Inf()),
    Lub    -> @lub(_,_),
    Glb    -> @glb(_,_)
}

// Simple Interval Analysis for analyzing value ranges of program variables

.type Node <: symbol
.type Variable <: symbol
.decl Edge(n:Node,succ: Node)
.decl Set_Value(n:Node,v:Variable, value:number)
.decl Increment_Value(n:Node,v:Variable,inc:number)
.decl Restrict_Value(n:Node, v:Variable, i:Interval<>)

/* Encoding the program:
v = 0;
while(v <= 100) {
    v = v + 2;
}
*/
Edge("start","start_to_head").
Edge("start_to_head", "head").
Edge("head","cond").
Edge("cond","incr").
Edge("incr","incr_to_head").
Edge("incr_to_head","head").
Edge("head","not cond").
Edge("not cond","end").

Set_Value("start","v", 0).
Restrict_Value("cond","v", $I($MinusInf(), $Cst(100))).
Restrict_Value("not cond","v", $I($Cst(101), $Inf())).
Increment_Value("incr", "v", 2).

// Possible values for v after statement n, expressed with an interval
// for instance: Values("head", "v", [0, 50])
.decl Values(
    n:Node,
    v:Variable,
    i:Interval<>)

.output Values()

Values(n, v, $I($Cst(x), $Cst(x))) :-
    Set_Value(n, v, x).

Values(n, v, i) :-
    Values(pred, v, i),
    Edge(pred, n),
    !Set_Value(n, v, _),
    !Increment_Value(n, v, _),
    !Restrict_Value(n, v, _).

Values(n, v, @incr(i, x)) :-
    Values(pred, v, i),
    Edge(pred, n),
    Increment_Value(n, v, x).

Values(n, v, x) :-
    Values(pred, v, x),
    Edge(pred, n),
    Restrict_Value(n, v, x).

