Proofs and Refutations Using Z3
blog.janestreet.com
blog.janestreet.com
That being said, model checkers find counter-examples. This is not the same as a formal proof. Just because a counter-example cannot be found does not mean that a given property has been proven. It is _extremely_ important to understand that point. Model checking, combined with unit testing, is a formidable tool that should be used whenever possible. But, don't assume that model checking is the same as a proof. The subtle difference does matter, and it can bite you.
It is possible to write formal proofs about software, using Calculus of Constructions, Separation Logic, Hoare Logic, etc. However, this is much harder than using a model checker. For 95% of applications, a model checker is good enough.
A bounded model checker on the other hand, checks the property for a given depth 'k', and hence the result is not applicable to a complete run.
In practice, it is all engineering, so anything can happen unless the model checker has been model checked.
I've been far down that rabbit hole, and I've found cases where certain model checkers fail to find counterexamples that other model checkers find. Sometimes, this is due to errors in one or more of the checkers. Sometimes this is due to differences in representation. But, ultimately, the argument is epistemological. There is a corollary to the phrase: "Absence of proof isn't proof of absence": absence of a counterexample isn't an absence of a contradiction.
As I've said, I love model checkers. But, they are not perfect, nor are they a panacea.
https://www21.in.tum.de/~lammich/pub/nfm2016_por.pdf
Lammich was a name I recognized immediately for his work converting functional data structures to imperative ones in Isabelle/HOL. He and his collaborators have done quite a few interesting things so I'll just leave you the whole list:
https://www21.in.tum.de/~lammich/
Far as lightweight methods, I recently summarized some recommendations with supporting case studies on Schneier's blog based on a message I sent someone trying to sell management on verification. It's a draft that I'm getting feedback on from various people rather than something I'm 100% solid on. The SPARK work combined with their book is still one of easiest methods in terms of automation achieved for covering specific properties that are often significant.
https://www.schneier.com/blog/archives/2018/02/friday_squid_...
As others have said, an exhaustive model checker failing to find a counterexample is a proof. That you trust proofs more because you haven't yet seen a bug in a proof assistant speaks only to your personal experience, not to any logical truism.
(That said, most models are not finite, and thus cannot be exhaustively checked. This is where proof systems do have a leg up. But that has nothing to do with bugs or representation of the system under test.)
When Z3 first came out, I built a machine model for a subset of ARMv7 and ran into a few cases that confused Z3, but worked fine in an equivalent MiniSat. However, this was years ago, and it appears -- although I have not verified this -- that the code in Z3 that I narrowed down in preparation to filing a bug report has already been fixed. The machine model has succumbed to bit rot; I abandoned the effort for a model I built on top of Coq. But, it would be interesting to attempt to fire it up again to see if it works now, and if so, use that to perform a binary search to find out when the fix was applied.
It shouldn't be hard to create an example where two model checkers differ. Check current bug reports for two model checkers, and build a model that exploits the bug in one model checker but in which the other model checker works. These code bases are complex. They are increasingly infrequent, as the developers working on these model checkers are quite diligent, but subtle errors do exist.
So it's possible for mainstream SAT solvers to have errors, but I imagine their default configurations are very thoroughly tested.
But yes it is strange that it doesn't verify its outputs. On the other hand SAT solvers want to be as fast as possible and there shouldn't be a need to do it if the solver is operating correctly.
This post deals with a significantly harder problem, though.
For example, Python version of the “x + +0 = x” check looks like this:
from z3 import *
s = SolverFor('QF_FP')
x = FP('x', FPSort(11, 53))
z = fpPlusZero(FPSort(11, 53))
r = RNE()
s.add(Not(fpAdd(r, x, z) == x))
print(s.check())
print(s.model())
(Except that I hardcoded rounding-mode, because I couldn't figure out how to make an unknown one. :-/)Hwayne has write-ups on both of those concepts:
learntla.com
https://hillelwayne.com/post/pbt-contracts/
Here's one on contracts that even your management might like:
https://www.win.tue.nl/~wstomv/edu/2ip30/references/design-b...
Other than that, integrating TLA+ with your dev workflow is very straightforward if you're dealing with concurrency or distributed systems. In other domains its value is less obvious.
You might also take a look at the P language, which will model-check your code if you add the right hooks.