@@ -4495,8 +4495,7 @@ defmodule Module.Types.Descr do
44954495 _ ->
44964496 case bdd_compare ( bdd1 , bdd2 ) do
44974497 { :lt , { lit1 , c1 , u1 , d1 } , bdd2 } ->
4498- { lit1 , bdd_difference ( bdd_union ( c1 , u1 ) , bdd2 ) , :bdd_bot ,
4499- bdd_difference ( bdd_union ( d1 , u1 ) , bdd2 ) }
4498+ { lit1 , bdd_difference ( c1 , bdd2 ) , bdd_difference ( u1 , bdd2 ) , bdd_difference ( d1 , bdd2 ) }
45004499
45014500 { :gt , bdd1 , { lit2 , c2 , u2 , d2 } } ->
45024501 # The proper formula is:
@@ -4510,10 +4509,44 @@ defmodule Module.Types.Descr do
45104509
45114510 { :eq , { lit , c1 , u1 , d1 } , { _ , c2 , u2 , d2 } } ->
45124511 cond do
4513- u2 == :bdd_bot and d2 == :bdd_bot ->
4514- { lit , bdd_difference ( c1 , c2 ) , bdd_difference ( u1 , c2 ) , bdd_union ( u1 , d1 ) }
4512+ c2 == :bdd_bot and d2 == :bdd_bot ->
4513+ { lit , bdd_difference ( c1 , u2 ) , bdd_difference ( u1 , u2 ) , bdd_difference ( d1 , u2 ) }
4514+
4515+ u2 == :bdd_bot ->
4516+ cond do
4517+ d2 == :bdd_bot ->
4518+ { lit , bdd_difference ( c1 , c2 ) , bdd_difference ( u1 , c2 ) , bdd_union ( u1 , d1 ) }
4519+
4520+ c2 == :bdd_bot ->
4521+ { lit , bdd_union ( u1 , c1 ) , bdd_difference ( u1 , d2 ) , bdd_difference ( c1 , c2 ) }
4522+
4523+ true ->
4524+ # If d2 or c2 are bottom, we can remove one union.
4525+ #
4526+ # For example, if d2 is bottom, we have this BDD:
4527+ #
4528+ # {l, (C1 or U1) and not C2, U1 and not C2, D1 or U1}
4529+ #
4530+ # Where the constrained part is:
4531+ #
4532+ # (l and (C1 or U1) and not C2)
4533+ #
4534+ # Which expands to:
4535+ #
4536+ # (l and C1 and not C2) or (l and U1 and not C2)
4537+ #
4538+ # Given (U1 and not C2) is already part of the uncertain/union,
4539+ # we can skip (l and U1 and not C2), and we end up with:
4540+ #
4541+ # {l, C1 and not C2, U1 and not C2, D1 or U1}
4542+ #
4543+ # Which are the formulas used above.
4544+ { lit , bdd_difference ( bdd_union ( u1 , c1 ) , c2 ) ,
4545+ bdd_difference ( bdd_difference ( u1 , c2 ) , d2 ) ,
4546+ bdd_difference ( bdd_union ( u1 , d1 ) , d2 ) }
4547+ end
45154548
4516- u1 == u2 ->
4549+ u1 == :bdd_bot or u1 == u2 ->
45174550 { lit , bdd_difference_union ( c1 , c2 , u2 ) , :bdd_bot ,
45184551 bdd_difference_union ( d1 , d2 , u2 ) }
45194552
@@ -4574,15 +4607,20 @@ defmodule Module.Types.Descr do
45744607 bdd_intersection ( bdd1 , d2 ) }
45754608
45764609 # Notice that (l ? c1, u1, d1) and (l ? c2, u2, d2) is, on paper, equivalent to
4577- # [(l /\ c1) \/ u1 \/ (not l /\ d1)] and [(l /\ c2) \/ u2 \/ (not l /\ d2)]
4610+ # [(l and c1) or u1 or (not l and d1)] and [(l and c2) or u2 or (not l and d2)].
4611+ #
45784612 # which is equivalent, by distributivity of intersection over union, to
4579- # l /\ [(c1 /\ c2) \/ (c1 /\ u2) \/ (u1 /\ c2)]
4580- # \/ (u1 /\ u2)
4581- # \/ [(not l) /\ ((d1 /\ u2) \/ (d1 /\ d2) \/ (u1 /\ d2))]
4613+ #
4614+ # l and [(c1 and c2) or (c1 and u2) or (u1 and c2)]
4615+ # or (u1 and u2)
4616+ # or [(not l) and ((d1 and u2) or (d1 and d2) or (u1 and d2))]
4617+ #
45824618 # which is equivalent, by factoring out c1 in the first disjunct, and d1 in the third, to
4583- # l /\ [c1 /\ (c2 \/ u2)] \/ (u1 /\ c2)
4584- # \/ (u1 /\ u2)
4585- # \/ (not l) /\ [d1 /\ (u2 \/ d2) \/ (u1 /\ d2)]
4619+ #
4620+ # l and [c1 and (c2 or u2)] or (u1 and c2)
4621+ # or (u1 and u2)
4622+ # or (not l) and [d1 and (u2 or d2) or (u1 and d2)]
4623+ #
45864624 # This last expression gives the following implementation:
45874625 { :eq , { lit , c1 , u1 , d1 } , { _ , c2 , u2 , d2 } } ->
45884626 { lit , bdd_union ( bdd_intersection_union ( c1 , c2 , u2 ) , bdd_intersection ( u1 , c2 ) ) ,
0 commit comments