Skip to content

Commit 78e0398

Browse files
committed
Implement leaf nodes for difference, negation, and dnf
1 parent 20564ba commit 78e0398

File tree

1 file changed

+51
-18
lines changed

1 file changed

+51
-18
lines changed

lib/elixir/lib/module/types/descr.ex

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4470,29 +4470,50 @@ defmodule Module.Types.Descr do
44704470
{bdd, :bdd_bot} ->
44714471
bdd
44724472

4473-
{:bdd_top, {lit, c2, u2, d2}} ->
4474-
bdd_negation({lit, c2, u2, d2})
4473+
{:bdd_top, bdd} ->
4474+
bdd_negation(bdd)
4475+
4476+
{bdd1, bdd2} ->
4477+
case bdd_compare(bdd1, bdd2) do
4478+
{:lt, {lit1, c1, u1, d1}, bdd2} ->
4479+
{lit1, bdd_difference(bdd_union(c1, u1), bdd2), :bdd_bot,
4480+
bdd_difference(bdd_union(d1, u1), bdd2)}
4481+
4482+
{:gt, bdd1, {lit2, c2, u2, d2}} ->
4483+
{lit2, bdd_difference(bdd1, bdd_union(c2, u2)), :bdd_bot,
4484+
bdd_difference(bdd1, bdd_union(d2, u2))}
4485+
4486+
{:eq, {lit, c1, u1, d1}, {_, c2, u2, d2}} ->
4487+
cond do
4488+
u2 == :bdd_bot and d2 == :bdd_bot ->
4489+
{lit, bdd_difference(c1, c2), bdd_difference(u1, c2), bdd_union(u1, d1)}
4490+
4491+
u1 == u2 ->
4492+
{lit, bdd_difference_union(c1, c2, u2), :bdd_bot,
4493+
bdd_difference_union(d1, d2, u2)}
4494+
4495+
true ->
4496+
{lit, bdd_difference(bdd_union(c1, u1), bdd_union(c2, u2)), :bdd_bot,
4497+
bdd_difference(bdd_union(d1, u1), bdd_union(d2, u2))}
4498+
end
44754499

4476-
{{lit, c1, u1, d1}, {lit, c2, u2, d2}} ->
4477-
cond do
4478-
u2 == :bdd_bot and d2 == :bdd_bot ->
4479-
{lit, bdd_difference(c1, c2), bdd_difference(u1, c2), bdd_union(u1, d1)}
4500+
{:eq, {_, _}, {_, _}} ->
4501+
:bdd_bot
44804502

4481-
u1 == u2 ->
4482-
{lit, bdd_difference_union(c1, c2, u2), :bdd_bot, bdd_difference_union(d1, d2, u2)}
4503+
{:eq, _, {lit, c2, u2, _d2}} ->
4504+
{lit, bdd_negation(bdd_union(c2, u2)), :bdd_bot, :bdd_bot}
44834505

4484-
true ->
4485-
{lit, bdd_difference(bdd_union(c1, u1), bdd_union(c2, u2)), :bdd_bot,
4486-
bdd_difference(bdd_union(d1, u1), bdd_union(d2, u2))}
4506+
{:eq, {lit, _c1, u1, d1}, _} ->
4507+
{lit, :bdd_bot, :bdd_bot, bdd_union(d1, u1)}
44874508
end
4509+
end
4510+
end
44884511

4489-
{{lit1, c1, u1, d1}, {lit2, _, _, _} = bdd2} when lit1 < lit2 ->
4490-
{lit1, bdd_difference(bdd_union(c1, u1), bdd2), :bdd_bot,
4491-
bdd_difference(bdd_union(d1, u1), bdd2)}
4492-
4493-
{bdd1, {lit2, c2, u2, d2}} ->
4494-
{lit2, bdd_difference(bdd1, bdd_union(c2, u2)), :bdd_bot,
4495-
bdd_difference(bdd1, bdd_union(d2, u2))}
4512+
defp bdd_compare(bdd1, bdd2) do
4513+
case {bdd_head(bdd1), bdd_head(bdd2)} do
4514+
{lit1, lit2} when lit1 < lit2 -> {:lt, bdd_expand(bdd1), bdd2}
4515+
{lit1, lit2} when lit1 > lit2 -> {:gt, bdd1, bdd_expand(bdd2)}
4516+
_ -> {:eq, bdd1, bdd2}
44964517
end
44974518
end
44984519

@@ -4551,6 +4572,7 @@ defmodule Module.Types.Descr do
45514572
# Lazy negation: eliminate the union, then perform normal negation (switching leaves)
45524573
defp bdd_negation(:bdd_top), do: :bdd_bot
45534574
defp bdd_negation(:bdd_bot), do: :bdd_top
4575+
defp bdd_negation({_, _} = pair), do: {pair, :bdd_bot, :bdd_bot, :bdd_top}
45544576

45554577
defp bdd_negation({lit, c, u, d}) do
45564578
{lit, bdd_negation(bdd_union(c, u)), :bdd_bot, bdd_negation(bdd_union(d, u))}
@@ -4561,6 +4583,10 @@ defmodule Module.Types.Descr do
45614583
defp bdd_to_dnf(acc, _pos, _neg, :bdd_bot), do: acc
45624584
defp bdd_to_dnf(acc, pos, neg, :bdd_top), do: [{pos, neg} | acc]
45634585

4586+
defp bdd_to_dnf(acc, pos, neg, {_, _} = lit) do
4587+
[{[lit | pos], neg} | acc]
4588+
end
4589+
45644590
# Lazy node: {lit, C, U, D} ≡ (lit ∧ C) ∪ U ∪ (¬lit ∧ D)
45654591
defp bdd_to_dnf(acc, pos, neg, {lit, c, u, d}) do
45664592
# U is a bdd in itself, we accumulate its lines first
@@ -4571,6 +4597,13 @@ defmodule Module.Types.Descr do
45714597
|> bdd_to_dnf(pos, [lit | neg], d)
45724598
end
45734599

4600+
@compile {:inline, bdd_expand: 1, bdd_head: 1}
4601+
defp bdd_expand({_, _} = pair), do: {pair, :bdd_top, :bdd_bot, :bdd_bot}
4602+
defp bdd_expand(bdd), do: bdd
4603+
4604+
defp bdd_head({lit, _, _, _}), do: lit
4605+
defp bdd_head(pair), do: pair
4606+
45744607
## Pairs
45754608

45764609
# To simplify disjunctive normal forms of e.g., map types, it is useful to

0 commit comments

Comments
 (0)