@@ -4470,29 +4470,50 @@ defmodule Module.Types.Descr do
4470
4470
{ bdd , :bdd_bot } ->
4471
4471
bdd
4472
4472
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
4475
4499
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
4480
4502
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 }
4483
4505
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 ) }
4487
4508
end
4509
+ end
4510
+ end
4488
4511
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 }
4496
4517
end
4497
4518
end
4498
4519
@@ -4551,6 +4572,7 @@ defmodule Module.Types.Descr do
4551
4572
# Lazy negation: eliminate the union, then perform normal negation (switching leaves)
4552
4573
defp bdd_negation ( :bdd_top ) , do: :bdd_bot
4553
4574
defp bdd_negation ( :bdd_bot ) , do: :bdd_top
4575
+ defp bdd_negation ( { _ , _ } = pair ) , do: { pair , :bdd_bot , :bdd_bot , :bdd_top }
4554
4576
4555
4577
defp bdd_negation ( { lit , c , u , d } ) do
4556
4578
{ lit , bdd_negation ( bdd_union ( c , u ) ) , :bdd_bot , bdd_negation ( bdd_union ( d , u ) ) }
@@ -4561,6 +4583,10 @@ defmodule Module.Types.Descr do
4561
4583
defp bdd_to_dnf ( acc , _pos , _neg , :bdd_bot ) , do: acc
4562
4584
defp bdd_to_dnf ( acc , pos , neg , :bdd_top ) , do: [ { pos , neg } | acc ]
4563
4585
4586
+ defp bdd_to_dnf ( acc , pos , neg , { _ , _ } = lit ) do
4587
+ [ { [ lit | pos ] , neg } | acc ]
4588
+ end
4589
+
4564
4590
# Lazy node: {lit, C, U, D} ≡ (lit ∧ C) ∪ U ∪ (¬lit ∧ D)
4565
4591
defp bdd_to_dnf ( acc , pos , neg , { lit , c , u , d } ) do
4566
4592
# U is a bdd in itself, we accumulate its lines first
@@ -4571,6 +4597,13 @@ defmodule Module.Types.Descr do
4571
4597
|> bdd_to_dnf ( pos , [ lit | neg ] , d )
4572
4598
end
4573
4599
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
+
4574
4607
## Pairs
4575
4608
4576
4609
# To simplify disjunctive normal forms of e.g., map types, it is useful to
0 commit comments