-
Notifications
You must be signed in to change notification settings - Fork 2
Remove explicit IO
from our SMT interface
#99
Conversation
which will later be handled in an outer unsafePerformIO loop
typed-process instead of the lower level process library.
default.nix and shell.nix here?
broken tests now. Need to investigate
The last commit broke our tests. Our session with the solver now only sends empty
For the record, this is the same part of the session with the solver from commit 96b78f4 (with the compilation error fixed)
|
… can hardly translate anything, leaving us only with empty constraints
While stripping everything Pirouette-specific from our API with the SMT solver, I noticed that we rely on |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All looks good, modulo a couple of nitpicks and maybe pushMStack
/popMStack
stuff.
@@ -60,14 +61,15 @@ data Branch lang meta = Branch | |||
newTerm :: TermMeta lang meta | |||
} | |||
|
|||
-- TODO: Maybe this should be merged with 'LanguageSMT' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there (or would there be) any useful instances of LanguageSMT
that are not LanguageSMTBranches
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our implementation requires both instances to run the symbolic evaluation, so I guess it doesn't really matter, any lang
must be LanguageSMT lang
and LanguageSMTBranches lang
.
I'm under the impression that these classes were separated because certain types used inside LanguageSMTBranches
are not available where LanguageSMT
is at and would require some puzzle solving to find non-cyclical imports to satisfy everything. I decided to leave it untouched for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be a good moment to rename those classes. The general idea is:
LanguageBuiltins --> defines the built-ins (both terms and types)
| \
| LanguageBuiltinTypes --> defines the typing rules of each built-in term
|
LanguageSMT --> defines translation of built-ins into SMT
| (not every term can be translated)
|
LanguageSMTBranches --> defines at which points the symbolic evaluator has to do sth. special
on that sense, LanguageSMTBranches
could well be renamed to LanguageSymEval
or something similar.
To give you a difference, the LanguageSMT
translation of if ... then ... else ...
uses the ifthenelse
primitive in Z3. However, the LanguageSMTBranches
translation specifies that when an if
is found, two new branches must be created:
- Add
condition = True
to the list of known things, continue with thethen
term, - Add
condition = False
to the list of known things, continue with theelse
term.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I won't do that in this PR, I'll do it on the next, which will remove the Logger
too. I like LanguageSymEval
!
|
||
-- |If a function can be declared as an uninterpreted function, returns | ||
-- the type of its arguments and the type of its result. | ||
supportedUninterpretedFunction :: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does supported
part of the name mean? Does it mean that the type could be converted (judging from the implementation), or something else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
previously, we were using declareAsManyUninterpretedFunctinosAsPossible
inside initSolver
, and initSolver
would return the list of names that managed to be declared. Those that we don't "support", just get silently ignored, which was fine but it adds a dependency between initSolver
and everything else.
I split declareAsManyUninterpretedFunctionsAsPossible
into two: first give me the list of functions that I know I can declared (because we've managed to translate their types already), then declare then in initSolver
. Now, I don't need the result of initSolver
to have the set of knownNames
.
I'll remove the old declareAsManyUninterpretedFunctionsAsPossible
and will update the comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I'll keep this unresolved so the comment is always visible, breaking the data dependencies is an important point of this PR)
This would be very welcome! I've struggled with this in the past, mostly because of |
@0xd34df00d thanks for the review! I fixed all I could on this iteration and I added a lock to edit: I removed the |
@serras, I hope to do this today! |
will bring it on the next one.
What
This PR does two large, but intertwined, pieces of work:
pirouette
to interact with a solver through:typed-process
to launch the SMT process instead of howSimpleSMT
used to do it.Partially applying something to
solve
should cause further calls to share that shared context. Here's a gist showing a little experiment I did in this direction: https://gist.github.com/VictorCMiraldo/b7c448bb2bcf4b49962082970d61f64aIt doesn't use that
solve
function just yet, we need some further cleanup (#106) to start using it. Nevertheless, the interface with the symbolic evaluation engine is already defined in terms of a problem GADT:It is only inside the interpretation of those problems that we interact directly with the solver; anywhere else in the symbolic engine we just call
solveProblem
for now and in a next PR, will become justsolve
.Why
Having an explicit
IO
monad (or aMonadIO m
constraint) simply because we need to talk to an SMT solver is a bad idea. For one, it means we cannot be lazy enough and are always performing more work than we should (#97); Secondly, this implies an unnecessary sentimentality to our backend: why can't we easily explore disjoint branches in parallel?