Simplifying a BDD relative to an implication

[Andersen2011] is the canonical BDD introduction that I read during grad school.

https://www.cmi.ac.in/~madhavan/courses/verification-2011/andersen-bdd.pdf

It describes an algorithm called `Simplify`, which simplifies one BDD relation to another. That is, given two BDDs representing functions `d` and `u`, `Simplify(d, u)` returns another BDD `u'` where `d ∧ u == d ∧ u'`.

For constraint sets, `d` will be an implication describing that two individual constraints simplify relative to each other, `c₁ → c₂`. (If `c₁` is true, then we know that `c₂` is true as well.) The simplification will remove parts of the BDD where we make a redundant check on `c₂` (that is, where we've already established that `c₁` is true, and therefore don't need to check `c₂`).

Here we specialize the `Simplify` algorithm where `d` is fixed to the implication `c₁ → c₂`.

The text of the algorithm from [Andersen2011] is:

fn Simplify(d, u) {
  if d = 0 then return 0
  else if u ≤ 1 then return u
  else if d = 1 then
    return Mk(var(u), Simplify(d, low(u)), Simplify(d, high(u)))
  else if var(d) = var(u) then
    if low(d) = 0 then return Simplify(high(d), high(u))
    else if high(d) = 0 then return Simplify(low(d), low(u))
    else return Mk(var(u),
                   Simplify(low(d), low(u)),
                   Simplify(high(d), high(u)))
  else if var(d) < var(u) then
    return Mk(var(d), Simplify(low(d), u), Simplify(high(d), u))
  else
    return Mk(var(u), Simplify(d, low(u)), Simplify(d, high(u)))
}

There are two cases to consider: `c₁ < c₂` and `c₂ < c₁`. (That is `c₁` appears before or after `c₂` in the BDD variable ordering; we're not talking about subtyping between the two constraints or the types they contain.)

Case 1: `c₁ < c₂`

d₁ = c₁ → c₂ = ¬c₁ ∨ c₂
var(d₁)  = c₁
low(d₁)  = 1
high(d₁) = d₂
var(d₂)  = c₂
low(d₂)  = 0
high(d₂) = 1
fn Simplify(d₁, u) {
  if u ≤ 1 then return u
  else if var(u) = c₁ then
    return Mk(c₁,
              Simplify(1, low(u)),
              Simplify(d₂, high(u)))
  else if c₁ < var(u) then
    return Mk(c₁, Simplify(1, u), Simplify(d₂, u))
  else
    return Mk(var(u), Simplify(d₁, low(u)), Simplify(d₁, high(u)))
}