Rule consistency or duplications¶
Here are the background types and functions we can use to represent the obligations and artifacts in these examples.
In [1]:
type obligations = {
sing_a_song: bool;
do_a_dance: bool;
}
type employee = {
name : string;
arrival_time : int;
obligations : obligations;
}
type state = {
emp: employee;
meeting_time: int;
}
let on_time st =
st.emp.arrival_time <= st.meeting_time
let is_late st =
not (on_time st)
Out[1]:
Now for a particular rules we can represent this modules, which have a common structure.
In [2]:
(* Employee E must sing a song
if E is late for a meeting for n minutes
and n is greater than 3*)
module Rule0 = struct
let c1 st =
is_late st
let c2 st =
st.emp.arrival_time - st.meeting_time > 3
let cs st =
c1 st && c2 st
let s st =
st.emp.obligations.sing_a_song
let rule st =
s st <== cs st
end
Out[2]:
In [3]:
(*
Employee E must sing a song
if E is late for a meeting for n minutes
and n is greater than 1
*)
module Rule1 = struct
let c1 st =
is_late st
let c2 st =
st.emp.arrival_time - st.meeting_time > 1
let cs st =
c1 st && c2 st
let s st =
st.emp.obligations.sing_a_song
let rule st =
s st <== cs st
end
Out[3]:
We can ask questions about these rules such as if the statements overlap using Imandra's instance mechanism:
In [4]:
(* Do Rule0's and Rule1's conditions overlap? *)
instance (fun st -> (Rule0.c1 st) && (Rule1.c1 st))
Out[4]:
In [5]:
(* Employee E must sing a song
if E is late for a meeting for n minutes
and n is less than 3*)
module Rule2 = struct
let c1 st =
is_late st
let c2 st =
st.emp.arrival_time - st.meeting_time < 3
let cs st =
c1 st && c2 st
let s st =
st.emp.obligations.sing_a_song
let rule st =
s st <== cs st
end
Out[5]:
In [6]:
(* Employee E must do a dance
if E is late for a meeting for n minutes
and n is greater than 3*)
module Rule3 = struct
let c1 st =
is_late st
let c2 st =
st.emp.arrival_time - st.meeting_time > 3
let cs st =
c1 st && c2 st
let s st =
st.emp.obligations.do_a_dance
let rule st =
s st <== cs st
end
Out[6]:
In [7]:
(* Employee E must NOT sing a song
if E is late for a meeting for n minutes
and n is greater than 1 *)
module Rule3 = struct
let c1 st =
is_late st
let c2 st =
st.emp.arrival_time - st.meeting_time > 1
let cs st =
c1 st && c2 st
let s st =
not (st.emp.obligations.sing_a_song)
let rule st =
s st <== cs st
end
Out[7]:
In [8]:
(* Employee E must not sing a song
if E is late for a meeting for n minutes
and n is greater than 3 *)
module Rule4 = struct
let c1 st =
is_late st
let c2 st =
st.emp.arrival_time - st.meeting_time > 3
let cs st =
c1 st && c2 st
let s st =
not (st.emp.obligations.sing_a_song)
let rule st =
s st <== cs st
end
Out[8]:
In [9]:
(* Employee E must do a dance
if E is late for a meeting for n minutes
and n is greater than 3 *)
module Rule5 = struct
let c1 st =
is_late st
let c2 st =
st.emp.arrival_time - st.meeting_time > 1
let cs st =
c1 st && c2 st
let s st =
st.emp.obligations.do_a_dance
let rule st =
s st <== cs st
end
Out[9]:
In [10]:
(* Employee E must sing a song
if E is late for a meeting for n minutes
and n is less than 3 *)
module Rule6 = struct
let c1 st =
is_late st
let c2 st =
st.emp.arrival_time - st.meeting_time < 3
let cs st =
c1 st && c2 st
let s st =
st.emp.obligations.sing_a_song
let rule st =
s st <== cs st
end
Out[10]:
In [11]:
(* Employee E must not sing a song
if E is late for a meeting for n minutes
and n is greater than 1 *)
module Rule7 = struct
let c1 st =
is_late st
let c2 st =
st.emp.arrival_time - st.meeting_time > 1
let cs st =
c1 st && c2 st
let s st =
not (st.emp.obligations.sing_a_song)
let rule st =
s st <== cs st
end
Out[11]:
In [12]:
(* Employee E must not sing a song
if E is late for a meeting for n minutes
and n is less than 3 *)
module Rule8 = struct
let c1 st =
is_late st
let c2 st =
st.emp.arrival_time - st.meeting_time < 3
let cs st =
c1 st && c2 st
let s st =
not (st.emp.obligations.sing_a_song)
let rule st =
s st <== cs st
end
Out[12]:
Let's pose some queries about the relationships of these rules¶
In [13]:
(* Do the conditions of rules 0 and 1 overlap? *)
instance (fun st -> Rule0.cs st && Rule1.cs st)
Out[13]:
In [14]:
(* Do the statements of rules 0 and 1 overlap? *)
instance (fun st -> Rule0.s st && Rule1.s st)
Out[14]:
In [15]:
(* We can encode these as checks on rules.
We prefix with `v` if `verify` should be used, else with `i` if `instance` should be used. *)
let v_check_1 r1_cs r1_s r2_cs r2_s st =
r1_s st = r2_s st && r1_cs st = r2_cs st
Out[15]:
In [16]:
(* For example, we can do check1 for Rule0 and Rule0 *)
verify (fun st -> v_check_1 Rule0.cs Rule0.s Rule0.cs Rule0.s st)
Out[16]:
In [17]:
(* And similarly for Rule0 and Rule1 *)
verify (fun st -> v_check_1 Rule0.cs Rule0.s Rule1.cs Rule1.s st)
Out[17]:
In [18]:
(* Now let's consider check2: statements the same but conditions different (overlapping) *)
(* We do this with two checks, one universal and one existential: *)
let v_check2 r1_cs r1_s r2_cs r2_s st =
r1_s st = r2_s st
let i_check2 r1_cs r1_s r2_cs r2_s st =
r1_cs st && r2_cs st
Out[18]:
In [19]:
(* Let's check condition 2 for Rule0 and Rule1 -- we see it holds! *)
verify (fun st -> v_check2 Rule0.cs Rule0.s Rule1.cs Rule2.s st)
instance (fun st -> i_check2 Rule0.cs Rule0.s Rule1.cs Rule2.s st)
Out[19]:
In [20]:
(* Let's check condition 2 for Rule0 and Rule2 -- we see it does not hold! *)
verify (fun st -> v_check2 Rule0.cs Rule0.s Rule2.cs Rule2.s st)
instance (fun st -> i_check2 Rule0.cs Rule0.s Rule2.cs Rule2.s st)
Out[20]:
In [21]:
(* Now let's do check 7: contrary statements with same conditions *)
let v_check7 r1_cs r1_s r2_cs r2_s st =
(r1_s st <==> not(r2_s st)) && (r1_cs st = r2_cs st)
Out[21]:
In [22]:
(* We'll check this for Rule0 and Rule 4 *)
verify (fun st -> v_check7 Rule0.cs Rule0.s Rule4.cs Rule4.s st)
Out[22]:
In [23]:
(* Now let's check it for Rule0 and Rule5 -- we see it's not true! *)
verify (fun st -> v_check7 Rule0.cs Rule0.s Rule5.cs Rule5.s st)
Out[23]:
Let's look at a region decomp of a particular rule to get examples of its distinct behaviours.