@@ -4495,19 +4495,52 @@ 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 { lit2 , bdd_difference ( bdd1 , bdd_union ( c2 , u2 ) ) , :bdd_bot ,
45034502 bdd_difference ( bdd1 , bdd_union ( d2 , u2 ) ) }
45044503
45054504 { :eq , { lit , c1 , u1 , d1 } , { _ , c2 , u2 , d2 } } ->
45064505 cond do
4507- u2 == :bdd_bot and d2 == :bdd_bot ->
4508- { lit , bdd_difference ( c1 , c2 ) , bdd_difference ( u1 , c2 ) , bdd_union ( u1 , d1 ) }
4506+ c2 == :bdd_bot and d2 == :bdd_bot ->
4507+ { lit , bdd_difference ( c1 , u2 ) , bdd_difference ( u1 , u2 ) , bdd_difference ( d1 , u2 ) }
4508+
4509+ u2 == :bdd_bot ->
4510+ cond do
4511+ d2 == :bdd_bot ->
4512+ { lit , bdd_difference ( c1 , c2 ) , bdd_difference ( u1 , c2 ) , bdd_union ( u1 , d1 ) }
4513+
4514+ c2 == :bdd_bot ->
4515+ { lit , bdd_union ( u1 , c1 ) , bdd_difference ( u1 , d2 ) , bdd_difference ( c1 , c2 ) }
4516+
4517+ true ->
4518+ # If d2 or c2 are bottom, we can remove one union.
4519+ #
4520+ # For example, if d2 is bottom, we have this BDD:
4521+ #
4522+ # {l, (C1 or U1) and not C2, U1 and not C2, D1 or U1}
4523+ #
4524+ # Where the constrained part is:
4525+ #
4526+ # (l and (C1 or U1) and not C2)
4527+ #
4528+ # Which expands to:
4529+ #
4530+ # (l and C1 and not C2) or (l and U1 and not C2)
4531+ #
4532+ # Given (U1 and not C2) is already part of the uncertain/union,
4533+ # we can skip (l and U1 and not C2), and we end up with:
4534+ #
4535+ # {l, C1 and not C2, U1 and not C2, D1 or U1}
4536+ #
4537+ # Which are the formulas used above.
4538+ { lit , bdd_difference ( bdd_union ( u1 , c1 ) , c2 ) ,
4539+ bdd_difference ( bdd_difference ( u1 , c2 ) , d2 ) ,
4540+ bdd_difference ( bdd_union ( u1 , d1 ) , d2 ) }
4541+ end
45094542
4510- u1 == u2 ->
4543+ u1 == :bdd_bot or u1 == u2 ->
45114544 { lit , bdd_difference_union ( c1 , c2 , u2 ) , :bdd_bot ,
45124545 bdd_difference_union ( d1 , d2 , u2 ) }
45134546
@@ -4568,15 +4601,20 @@ defmodule Module.Types.Descr do
45684601 bdd_intersection ( bdd1 , d2 ) }
45694602
45704603 # Notice that (l ? c1, u1, d1) and (l ? c2, u2, d2) is, on paper, equivalent to
4571- # [(l /\ c1) \/ u1 \/ (not l /\ d1)] and [(l /\ c2) \/ u2 \/ (not l /\ d2)]
4604+ # [(l and c1) or u1 or (not l and d1)] and [(l and c2) or u2 or (not l and d2)].
4605+ #
45724606 # which is equivalent, by distributivity of intersection over union, to
4573- # l /\ [(c1 /\ c2) \/ (c1 /\ u2) \/ (u1 /\ c2)]
4574- # \/ (u1 /\ u2)
4575- # \/ [(not l) /\ ((d1 /\ u2) \/ (d1 /\ d2) \/ (u1 /\ d2))]
4607+ #
4608+ # l and [(c1 and c2) or (c1 and u2) or (u1 and c2)]
4609+ # or (u1 and u2)
4610+ # or [(not l) and ((d1 and u2) or (d1 and d2) or (u1 and d2))]
4611+ #
45764612 # which is equivalent, by factoring out c1 in the first disjunct, and d1 in the third, to
4577- # l /\ [c1 /\ (c2 \/ u2)] \/ (u1 /\ c2)
4578- # \/ (u1 /\ u2)
4579- # \/ (not l) /\ [d1 /\ (u2 \/ d2) \/ (u1 /\ d2)]
4613+ #
4614+ # l and [c1 and (c2 or u2)] or (u1 and c2)
4615+ # or (u1 and u2)
4616+ # or (not l) and [d1 and (u2 or d2) or (u1 and d2)]
4617+ #
45804618 # This last expression gives the following implementation:
45814619 { :eq , { lit , c1 , u1 , d1 } , { _ , c2 , u2 , d2 } } ->
45824620 { lit , bdd_union ( bdd_intersection_union ( c1 , c2 , u2 ) , bdd_intersection ( u1 , c2 ) ) ,
0 commit comments