0

If have a set of rules -

1 : If x then a

2 : If x then b

Then these rules shall be conflicting as we shall not know what is the action to be performed when x is triggered. Therefore -

Now suppose I want to check for consistency of rules such as -

1: If (100 < m < 120) and (200 < n < 220) then output = 200

2: If (110 < m < 120) and (200 < n <210) then output =220

Clearly rules 1 and 2 are conflicting because if m = 115 and n = 205, then output can be either 200 or 220.

Is there a way I can check for the consistency of the above rules using the Z3 library ? Or using the pure SMT-lib2 ? Pls help. If you can give me an example of the actual code which can be run on https://rise4fun.com/Z3/vd?frame=1&menu=0&course=1 I shall be really grateful.

Thank you

Razor21
  • 59
  • 1
  • 6

1 Answers1

1

Sure.

(declare-fun m () Int)
(declare-fun n () Int)

(define-fun rule1_applies () Bool (and (< 100 m) (< m 120) (< 200 n) (< n 220)))
(define-fun rule2_applies () Bool (and (< 110 m) (< m 120) (< 200 n) (< n 210)))

(declare-fun output0 () Int)

(define-fun output_rule1 () Int (ite rule1_applies 200 output0))
(define-fun output_rule2 () Int (ite rule2_applies 220 output0))

(assert (and rule1_applies rule2_applies (distinct output_rule1 output_rule2)))
(check-sat)
(get-value (m n))

With this, z3 produces:

sat
((m 111)
 (n 201))

Which is what you're looking for in this instance, I believe.

Note that when you have more than 2 rules, you probably want to be more careful in your modeling to say that some subset of rules fired instead of all of them like I did above. In case you have 2 rules, that ends up being the same thing, but if you have 3 rules, you want to allow for the possibilities of {1, 2}, {1, 3}, {2, 3}, and {1, 2, 3} all firing. This latter can be modeled by counting predicates, by making sure the number of ruleN_applies booleans that go high is at least two. Feel free to ask if you've further questions regarding that.

alias
  • 28,120
  • 2
  • 23
  • 40
  • Dear sir, thank you so much for the speedy and detailed response. Pardon me, but I am a complete beginner when it comes to z3 and smt. I have a small doubt - shouldn't the output be unsat ? Like according to the rules 1 and 2 I have given, if m=111 and n=201, then wont there be a conflict in choosing the value of output ( it can be 200 or 220). I am building an application that can detect this conflict in rules. Pls correct me if I am wrong. Thank you sir ! – Razor21 Jun 12 '18 at 20:26
  • Perhaps I don't understand what you're trying to do. Your own question stipulated `m=115, n=205` is a "conflicting" solution. How is that different than the solution `m=111, n=201` that you do not like? – alias Jun 12 '18 at 20:36
  • I am basically trying to use z3 to store rules and then check them for consistency. The output of the code should tell the user that the rules are conflicting or unsat, if there is any set of values that can fire conflicting action sequences on the same output variable. In this case, the output of my desired system should inform the user that the rules in the system are conflicting due to a value (m=111, n=201) leading to inconsistency due to different action on a single output variable. My output variable can only perform a single action at a time - either it can be 200 or 220 at any time – Razor21 Jun 12 '18 at 20:46
  • To make it clearer, consider the example of a health care application. Lets say I have a rule 1 which states if blood sugar is between 100 and 120 then give insulin = 1 ml and another rule 2 which states if blood sugar is between 110 and 130 then give insulin = 2ml. Pls note these are conflicting rules because in the case of blood sugar being = 115, we shall be in a dilemma as to which amount of insulin is to be administered. Can we write a script as the one you gave me for checking for this inconsistency ?? Thank you very very much for your helo - I appreciate it – Razor21 Jun 12 '18 at 20:51
  • That's ok. In this case, you should read the `sat` response as: Yes, there's a model and thus your rules are conflicting, and here's the conflicting values. And `unsat` would mean: I can't find a way to make your values produce inconsistent values, and thus they are all consistent. Does that make sense? – alias Jun 12 '18 at 20:59
  • In other words: We're modeling so that the SMT solver works by checking satisfiability of an inconsistent rule execution. The way we model is to say "can something go wrong?" And the sat solver saying `sat` means: yes, it can go wrong, and here's how. If it says `unsat`, then it's saying there's no way to make it go wrong. – alias Jun 12 '18 at 21:01
  • Dear Sir, thanks a lot for the answer ! Clears up a lot of things. Just 2 more doubts - 1. If I had 3 output variables, say outp1, outp2, outp3 - how would your code change ? 2. I am writing java code to generate the code understandable to z3 for input. What would be the best way to integrate the tool such that the code which is generated by my java program can be given to z3 for testing ? – Razor21 Jun 12 '18 at 21:15
  • I'd treat each output separately, and do a disjunction. (i.e., there's a violation if there's a violation for any of them.) For Java: Z3 has Java bindings (https://z3prover.github.io/api/html/namespacecom_1_1microsoft_1_1z3.html), you can use those. But probably not the easiest thing to do. An easier alternative would be to generate a text-file, call z3 on it, and read results back. (That way you're not bound to Z3 either.) Honestly, I'd first experiment with something like Python bindings which are a lot easier to use and move to Java once you're confident of the approach. – alias Jun 12 '18 at 21:19
  • Thank you Levent ! You have been extremely helpful ! I write a script in Java to generate the z3 code which shall be the input to z3. I appreciate your help ! Have a great day. Ps: I may have some doubts, so may post here again xD – Razor21 Jun 12 '18 at 21:28
  • No problem! That's what StackOverflow is for. – alias Jun 12 '18 at 23:14
  • Dear Sir, suppose I have a pair of rules - 1: ( If 100 – Razor21 Jun 13 '18 at 09:47
  • You should model each output separately, and form the disjunction. See here: https://rise4fun.com/Z3/VzWS – alias Jun 13 '18 at 15:37
  • Thanks a lot ! Its working for simple rules but when I start scripting for complex rules it becomes difficult. Suppose I have 2 rules of the form - 1: If (((100 < m < 120) or (200 < n < 220)) and (((110 – Razor21 Jun 17 '18 at 18:06
  • You can always define helper functions to simplify coding. This should do: https://rise4fun.com/Z3/GqFU – alias Jun 17 '18 at 19:00
  • Just have a doubt. Suppose I have a simple pair of rules such as - 1: If 100 – Razor21 Jun 18 '18 at 10:30
  • You should only put in a violation if an output is modified in the corresponding path. The tell tale sign is `(distinct output0_rule1)`. Note how you had only one thing to put in the call to `distinct` there. You should recognize those cases and drop them completely. (Or replace them with `false`). Then you'll have `unsat` result. That is, replace any `(distinct x)` where there's one formula `x` with the expression `false`. – alias Jun 18 '18 at 14:17
  • This is perfect. Your knowledge on z3 is great. Do you recommend any specific source I can study to understand this topic better? Thanks very very much – Razor21 Jun 18 '18 at 16:12
  • Read through this: https://rise4fun.com/z3/tutorial. It’ll be well worth your time. – alias Jun 18 '18 at 16:38
  • Thanks ! Just another small hiccup - Suppose I have a pair of rules 1: If (((100 < m < 200) or (100 < n < 200)) and (((100 – Razor21 Jun 20 '18 at 11:57
  • You grouped your formulas incorrectly. The calls to distinct should check the same output from different rules. (You mixed them up.) See here for the corrected version: https://rise4fun.com/Z3/WD5C – alias Jun 20 '18 at 16:23
  • Oh didnt see that ! Thank you again. I am compiling all of the examples and will post a pdf containing of all these examples that I have created with your immense help on the web for everyone to use. There is not a lot of material available on the web and it shall be very useful to beginners. – Razor21 Jun 20 '18 at 16:34
  • The thing you haven't tried so far, I suppose, is having, let's say, 3 rules. In that case the modeling will need to take into account what happens if any two or all three fire. In general, if you have N rules, you'll have to consider all subsets of size >= 2. There are tricks to encode these things concisely; feel free to ask if you try and have difficulties. – alias Jun 20 '18 at 16:39
  • I havent thought about that yet ! Dear sir, could you point me towards some particular example or some resource I can read from ? Formulating all the violations shall lead to 2^n-1 violations and the code shall be difficult I presume.... – Razor21 Jun 20 '18 at 17:09
  • You can keep the violation count linear in the number of outputs. In fact, the modifications should be minimal. Instead of `(and rule1_applies rule2_applies ... ruleN_applies)` for each violation clause, you'd use the `at-least` predicate to make sure there's at least 2 rules that are violated. See this for details: https://github.com/Z3Prover/z3/issues/960 – alias Jun 20 '18 at 18:16
  • Dear sir, I have tried using the at-least predicate as you said in the previous comment, but am facing some issue. My code is available at https://rise4fun.com/Z3/QEm0 . Could you please tell me if I am using it correctly or post a permalink ? Also since I am writing a general script which should be applicable in the case of '1' rule or 'n' rules, can the at-least predicate be used in every case or do I need to use it only if I have 2 or more rules. Do I need to exercise caution when I am using the at-least predicate in those cases ? – Razor21 Jun 22 '18 at 10:38
  • Is that the correct link? I only see two rules in there. – alias Jun 22 '18 at 18:00
  • Take a look at this: https://rise4fun.com/Z3/fH94 To answer your question: Yes, you can use this trick regardless of the number of rules you have. Note that call will always look like `(_ at_least 2)` in your case, regardless of how many rules are. (1, 2, or any number). It would even work if you have 0-rules for a particular variable actually; so it's quite general and scales linearly with the number of rules and outputs. – alias Jun 22 '18 at 18:40
  • This was gold. Thank you !. Just need another clarification : In case I have only 1 thing to put in the call to distinct, and I am using the (_at_least 2 ) predicate, do I still need to drop (distinct x) and replace it with false as you had mentioned in a previous comment ? Could you please tell me what should be done in these cases ? Thank you for your help !!! – Razor21 Jun 24 '18 at 11:45
  • Hi. I have written my script in java and am now testing it. The first set of rules are 1. 10 – Razor21 Jun 24 '18 at 14:37
  • Unfortunately `distinct` isn't doing the right thing in this case. You'll have to write a separate violation rule for each pair of formulas. (You no longer need the `at-least` predicate.) The number of violation-rules will be `n*(n-1)/2`, for `n` rules; which isn't terribly bad. Give that a try. – alias Jun 24 '18 at 16:58
  • As an alternative, you can keep the same structure, but instead of `distinct` you can use `not` and `=`; like this: https://rise4fun.com/Z3/FrRw Note that with two rules, this is equivalent to `distinct`, but with three-or-more rules, it is different semantics from `distinct` (since it will be true if any pair is violated), which is exactly what you want. – alias Jun 24 '18 at 17:05
  • In the example code you have given at - https://rise4fun.com/Z3/FrRw , can we extend this idea to any general example ? For example at https://rise4fun.com/Z3/KOce I have 2 pieces of code - first one using the old approach and the new one using the not and = approach. I have tested them individually and both seem to work. Are there any cases for which the not and = approach will not work according to you and I need to exercise caution for those cases ? – Razor21 Jun 24 '18 at 17:15
  • I think the `not/=` approach should work in all cases. (If there's a case it doesn't, I'd like to know!) – alias Jun 24 '18 at 17:26
  • Also, if you're going to go with `n*(n-1)/2` violations approach, you should not use the `at-least` predicate. For each pair, you should say if the corresponding rules both fire, than that pair should produce the same result. I think keeping the `at-least` approach and using `not/=` is your best bet. – alias Jun 24 '18 at 17:27
  • I think I'll be sticking to the not/= approach as it seems to be the simplest and most similar to the at-least predictate. And In case I have only 1 thing to put in the call to not = during the definition of the violation for the output variable, do I still need to drop the rule and and replace it with false as you had mentioned in a previous comment. Original Code - https://rise4fun.com/Z3/7yKG and same rules but modified not/= code ( some error ) - https://rise4fun.com/Z3/wTWu . Kindly confirm sir – Razor21 Jun 24 '18 at 18:13
  • Yes, if a variable is modified only in one path, you should not flag it as a violation, which means you should replace the `not/=` part with `false`. Like this: https://rise4fun.com/Z3/9Q7JW – alias Jun 24 '18 at 19:05
  • Perfect ! Thank you very very much – Razor21 Jun 24 '18 at 19:28
  • Hey. Suppose I have 2 rules 1. 10 – Razor21 Jun 26 '18 at 17:29
  • Equality ends up being too strong in this case, since you only want equality if the corresponding rules fire. You should generate all pairs and check for sameness, like this: https://rise4fun.com/Z3/67gz – alias Jun 26 '18 at 22:41
  • Hi. Thanks for the code but just a quick question - What if we have more than 1 output variables to be affected when a certain rule fires ? I understand that we should generate all pairs and then check for sameness, but how do we decide which output variable is affected. For example - on line 29 of the code you posted, output_rule1 and output_rule2 are chosen but why not output0_rule3 ? Are we only choosing the output rules corresponding to a particular rule ? Also, is this general and can be extended to any set of rules ? Thanks a lot for your help – Razor21 Jun 28 '18 at 12:26
  • Please ignore the previous comment. I have understood the concept. Thank you !! – Razor21 Jun 28 '18 at 17:48
  • In general, you should treat each output variable separately. You can "code" them all together, but from a logical standpoint, you should treat it as one program per output variable. – alias Jun 28 '18 at 18:32
  • Hi. I have coded using your new approach and just wanted to clarify something - Suppose I have only a single rule existing in the system - 1.10 – Razor21 Jun 30 '18 at 20:02
  • I think this doubt may be connected to my previous comment, but could you tell me why these pair of rules are said to be conflicting. 1. 10 – Razor21 Jun 30 '18 at 20:48
  • It's hard to keep track of your questions; and stack-overflow comments are not suitable for this purpose. You should formulate new questions and post them as such, so others can opine as well. Regarding your second program (last comment above), it's clearly conflicting when `abc=11` and `def=41`, so I'm not sure what your question is. – alias Jun 30 '18 at 21:33
  • Oh thank you ! My bad, didn't see that !! Thanks a lot !! – Razor21 Jul 01 '18 at 05:51
  • Regarding your program in https://rise4fun.com/Z3/jpyC: Note that those rules will never ever fire, since you said: `(and (range abc 10 20)(range abc 20 30)))`; There's no value `abc` that's both between `(10, 20)` and `(20, 30)` (open intervals). Perhaps you meant to use `or` instead of `and`? – alias Jul 01 '18 at 17:12
  • No, I did a mistake in filling the intervals and figured that out later.. Thanks !!! – Razor21 Jul 02 '18 at 12:08