Simpler unifiers for equations with fewer variables on one of the sides#2
Simpler unifiers for equations with fewer variables on one of the sides#2robertkleffner wants to merge 7 commits into
Conversation
|
I do development in Gitpod, which explains the presence of |
|
Cool! Ill take a look soon (a bit busy these days)
That's fine. |
|
@jacopol Do you want to take a look too? |
|
(If this is sound, we should probably add it to Flix too- right around here: https://github.com/flix/flix/blob/master/main/src/ca/uwaterloo/flix/language/phase/unification/BoolUnification.scala#L40) |
|
I've made a generalization of the special case discussed earlier. It handles the previous case, and a few more complex ones. This one so far seems vastly more useful in my type inference work, and maybe points in an interesting direction for a syntactically driven method of Boolean unification in general. Goal The previous special case handled equations of the form Any unification of two Boolean formulas where Results The results of the previous implementation continue to apply, as a single variable will trivially match with any Boolean equation in which it is not free. Additionally, we get nice unifiers for some more complex equations. Without the special case: With the special case: My inductive proof skills are rusty enough that proving this is sound is difficult for me at the moment. But it seems pretty sure right now, provided the implementation of syntactic matching has no bugs. Possibilities As mentioned before, this seems like it could be extended into a syntactic method for Boolean unification. I haven't fully fleshed it out, but I'll give it a try and if it seems promising (and generates smaller unifiers) I'll revisit with a separate PR. Thanks again for making this project available! It's been nice to have an area to focus solely on the Boolean aspect of type systems. |
|
It seems the new special case generates a unifier that looks most general, but actually isn't in a number of cases. I will adjust it to be slightly narrower so that it continues to handle the cases posted above, but with a correct most-general unifier. |
|
This is a very cool idea! I will take a closer look tomorrow. |
Because of a bug in the implementation or a fundamental issue? |
|
The key quote:
I think there are two questions here:
The last question can be resolved experimentally. My guess is that - as the examples suggest - syntactic unification would lead to smaller formulas! The most interesting question is then whether (1) is true. It feels like something that should be true, but I have not seen it mentioned in the literature, which is a bit puzzling. I am now playing with some examples to convince myself one way or the other. One final question:
|
|
In it's current state I believe the PR can generate a less-general unifier. At least, I couldn't figure out how to construct the unifier generated by the online variant from the one generated on my branch: There's maybe something here but I think it needs work. I'm almost inclined to revert my last commit because the previous special case seems to be on far more solid ground. For the smaller unifier generated by the current commit, it is clear that the substitution makes the equations equal, but the truth table is entirely different from the one generated by existing master. I'm not sure exactly how relevant that is, because different alpha-equal equations can have different truth tables even comparing on master alone: So I think I need to understand a little more clearly what 'more general' means and implies in the context of Boolean equations, because it's not as intuitive as for syntactic unification in non-Boolean terms. It seems intuitive that equations like the Any guidance on those differences? I'm looking through Term Rewriting and All That independently but any other insights are most welcome. |
|
Reverted after making a branch to maintain the experiment for now. |
|
I'm excited about this direction. We should indeed be able to solve simple standard unification problems efficiently. However, what would happen to this example: a ∨ b = p ∨ p? |
|
@jacopol Yes, you're right. That scenario was due to my not understanding the full implications of 'more general' in the context of Boolean equations. After some time revisiting the definition and a few examples more carefully, I now see why the syntactic approach is difficult to pursue. I had another idea for simpler unifiers for Even worse, after looking at Term Rewriting and All That, the I appreciate both of you taking the time to look into this (thanks for roping in Jaco @magnus-madsen). I'll try to make a better formalism to show that the current special case for equations with a single variable on one side generates true most-general unifiers. |
|
While the idea of syntactic unification may not work, both Jaco and I agreed that it is an interesting approach! So thanks for bringing it up; it lead to some interesting discussion offline. We also agree with the sentiment of focusing on unification of conjunctions (or disjunctions). Although we don't have any insights yet. (As a minor comment, while the syntactic approach does not give most general unifiers, we did discuss that there is probably no need for requiring the LHS and RHS to have disjoint variables because the syntactic "occurs check" already accounts for that scenario.) One other thing, in case you did not consider it, you/we could chose to represent Boolean formulas with BDDs or in the Boolean ring (as a polynomial). Note that the latter has a unique representation! That's an alternative to Boolean minimization. A better unification procedure would of course still be the holy grail... |
|
Quick thought: according to Term Rewriting and All That, Lowenheim's algorithm for unification generates MGUs from any unifier for a Boolean equation. In the book they start with a ground substitution, which ends up leading to big, intimidating MGUs that are harder to minimize. What if, as a starting solution in Lowenheim's method, one were to use a syntactic unifier? I have a branch on my fork that implements Lowenheim's method. I'll give this idea a shot, and if it doesn't work, at least I'll have another PR adding an option to use Lowenheim's method in the workbench. |
|
Do you have a good description / implementation of Lowenheim's method somewhere? |
|
I do! See PR #3. I can merge that with this PR and close that other PR, but I figured it would be nice to be able to review it independently. Lowenheim's method is surprisingly difficult to find any information about online. |
|
WRT the special case here, I may have made it unnecessary, so long as @jacopol's suggestion to start SVE with the single variable side is included. Experimentally it seems adding complementarity and absorption simplification checks to It does cause the If it turns out well I might change this PR to simply implement a few more simplification laws in |
…s minimal in a lot of common cases.
…ated twice by SVE.
|
No more special case Implemented @jacopol's suggestion along with some Boolean identity simplifications in Example Result Comparisons |
…rk for all free variable counts. A couple additional identities.
|
@robertkleffner Is there any way to reach you privately? Perhaps you could DM me on https://gitter.im/flix/Lobby ? |
Fixes #1
Goal
Boolean unification does not have unique MGUs, but should prefer to generate minimized and 'easy to understand' unifiers when possible. Boolean minimization techniques help in many scenarios, but there is no one technique that outperforms others in all cases. The change proposed by this PR handles a small but important special case: when one side of an equation is just a variable not contained in the other side of the equation.
Results
Without special case:
With special case:
Partial proof sketch
Conjecture: Given a Boolean equation
X = Eqn, where the variableXis not free inEqn, then[X --> Eqn]is a valid MGU forX = Eqn.Let
Xbe a Boolean variable,Eqna Boolean equation in whichXis not free, and letSbe the substitution[X --> Eqn]. Given thatXis not free inEqn, we know that applyingStoEqnwill have no effect. ApplyingStoXwill yieldEqn, and so applyingStoX = Eqnwill yieldEqn = Eqn, a syntactic equality of Boolean equations.Possibilities
It is possible that the special case is applied too conservatively. Currently, given
X = Eqn, the special case is only applied ifX ∉ free(Eqn). Maybe there is a similar special case that applies whenX ∈ free(Eqn), however the presence of negations ofXinEqnmake the case more complicated.