Conversation
|
Marked as draft as the curent implementation doesn't work due to #93. |
| """Define a new SMT recursive function with the given function declaration. | ||
| Replaces constants in `args` with bound variables. | ||
|
|
||
| >>> fact = Function('fact', IntSort(), IntSort()) |
There was a problem hiding this comment.
According to Z3, a recursive function must be declared using RecFunction instead of Function. If you try to add a definition using RecAddDefinition to a function declared with Function, Z3 will trigger an error.
There was a problem hiding this comment.
I had an implementation of RecFunction but it turned out exactly the same as Function. The reason for this distinction in z3 is because they have Z3_mk_func_decl and Z3_mk_rec_func_decl, here I believe we just need mkConst to declare a function, recursive or not.
There was a problem hiding this comment.
I could add RecFunction to maintain compatibility, but do you think we should restrict the usage of RecAddDefinition like z3 does?
There was a problem hiding this comment.
We have discussed this in the cvc5 team and the conclusion is:
- we should support the same functionality that z3 does, so to have a
RecFunctionmethod - we can also have extra functionality, so it's OK to support the case where we use
Function
|
@caioraposo @daniel-larraz I would be interested in picking this PR up because my project uses this functionality and I'm trying to add a cvc5 backend in addition to z3. However I've reviewed the code and I'm stumped on Caio's comment here: #108 (comment) Potential solutions I see: 1. I believe that #2 is closer to what Z3 does however, are there other parts of the cvc5 pythonic API that already do anything similar? |
This would simplify things here but would change the other cvc5 APIs as well. I'll push some changes shortly with a solution. |
|
@caioraposo Your current implementation (399bd09) doesn't seem to behave correctly. Consider the following example: Z3 returns |
|
What about storing the recursive definition in the Context object associated with the function body, and adding the definition to the Solver as soon as it is created? |
This commit adds support for defining functions (recursive or not) through defineFun and defineFunRec from the base API.
|
@caioraposo @daniel-larraz You can find a working snippet for using the "configure solver on creation" strategy here: https://github.com/mercari/cel-smt/blob/8c6fbf987c309c22d1d0da25bec9a382e9dec8c3/src/cel_smt/backend.py#L23 Please let me know if you'd like me to create a separate PR, I'm happy to do so. |
Can you confirm this works if you define a function after creating a solver? For example: s = SolverFor("UFLIA")
fact = Function('fact', IntSort(), IntSort())
n = Int('n')
RecAddDefinition(fact, n, If(n == 0, 1, n * fact(n - 1)))
s.add(Not(fact(5) == 120))
print(s.check())I don't know how I could test your code. |
|
I think you can open a PR or point to your working branch, just to make it easier to review and test. It's difficult to know just based on the snippet you provided. |
This commit adds support for defining functions (recursive or not) through defineFun and defineFunRec from the base API.