@@ -5878,107 +5878,96 @@ defmodule Module.Types.Descr do
58785878
58795879 ## Optimize differences
58805880
5881- # For the right-side being a leaf, we have:
5881+ # We have two formulas for differences.
58825882 #
5883- # ((a1 and C1) or U1 or (not a1 and D1)) and not a2
5883+ # ## When D1 = bottom
58845884 #
5885- # If disjoint?(a1, a2), we end up with:
5885+ # (((a_diff and not D2) or (a_int and not C2)) and C1 and not U2) or (U1 and not B2)
58865886 #
5887- # ( a1 and C1) or (U1 and not a2) or (not a1 and D1 and not a2)
5887+ # If disjoint, a_diff is a1 and a_int is none:
58885888 #
5889- # If subtype? (a1, a2), we end up with:
5889+ # (a1 and C1 and not D2 and not U2) or (U1 and not B2)
58905890 #
5891- # (U1 and not a2) or (D1 and not a2)
5891+ # If subtype, a_diff is none and a_int is a1:
58925892 #
5893- # If one key difference, then we compute the difference
5894- # and the union of said keys, returning a_union and a_diff:
5893+ # (a1 and C1 and not C2 and not U2) or (U1 and not B2)
58955894 #
5896- # ((a1 and C1) or U1 or (not a1 and D1)) and not a2
5897- # (a_diff and C1) or (U1 and not a2) or (not a_union and D1)
5895+ # In the snippet below we also enforce that C1 is top for simplicity.
58985896 #
5899- defp bdd_difference ( { a1 , c1 , u1 , d1 } = bdd1 , bdd_leaf ( _ , _ ) = bdd2 , leaf_compare )
5900- when is_tuple ( bdd2 ) do
5901- case leaf_compare . ( a1 , bdd2 , :union ) do
5902- :disjoint ->
5903- res =
5904- bdd_union (
5905- bdd_difference ( u1 , bdd2 , leaf_compare ) ,
5906- bdd_difference ( { a1 , :bdd_bot , :bdd_bot , d1 } , bdd2 )
5907- )
5908-
5909- if c1 == :bdd_bot , do: res , else: bdd_union ( res , { a1 , c1 , :bdd_bot , :bdd_bot } )
5910-
5911- { :one_key_difference , a_diff , a_union } ->
5912- bdd_intersection ( a_diff , c1 )
5913- |> bdd_union ( bdd_difference ( u1 , bdd2 , leaf_compare ) )
5914- |> bdd_union ( bdd_difference ( d1 , a_union , leaf_compare ) )
5915-
5916- :subtype ->
5917- bdd_union ( bdd_difference ( u1 , bdd2 , leaf_compare ) , bdd_difference ( d1 , bdd2 , leaf_compare ) )
5918-
5919- :none ->
5920- bdd_difference ( bdd1 , bdd2 )
5921- end
5922- end
5923-
5924- # For the left-side being a leaf, we have:
5925- #
5926- # a1 and not ((a2 and C2) or U2 or (not a2 and D2))
5927- # a1 and not (a2 and C2) and not U2 and (a2 or not D2)
5928- #
5929- # If disjoint?(a1, a2):
5930- #
5931- # a1 and not (a2 and C2) = a1 (a2 and C2 is subset of a2, disjoint from a1)
5932- # a1 and (a2 or not D2) = a1 and not D2 (a1 and a2 = bottom)
5933- #
5934- # Result: a1 and not D2 and not U2
5935- #
5936- # If subtype?(a1, a2):
5937- #
5938- # a1 and not (a2 and C2) = a1 and not C2 (a1 and not a2 = bottom)
5939- # a1 and (a2 or not D2) = a1 (a1 and a2 = a1)
5940- #
5941- # Result: a1 and not C2 and not U2
5897+ # ## When C2 = top
59425898 #
5943- # If one key difference, then we compute the difference
5944- # and the intersection of said keys, returning a_int and a_diff:
5899+ # ((a_diff and C1) or (U1 and not a2) or (not a_union and D1)) and not U2 and not D2
59455900 #
5946- # a1 and not (a2 and C2) and not U2 and (a2 or not D2)
5947- # ((a1 and not a2) or (a1 and not C2)) and not U2 and (a2 or not D2)
5948- # (a_diff or (a1 and not C2)) and not U2 and (a2 or not D2)
5901+ # If disjoint, a_diff is a1 and a_union is a1 or a2:
59495902 #
5950- # Now distribute into (a2 or not D2):
5903+ # ((a1 and C1) or (U1 and not a2) or ( not a1 and D1 and not a2)) and not U2 and not D2
59515904 #
5952- # ((a_diff and (a2 or not D2)) or
5953- # ((a1 and not C2) and (a2 or not D2))) and not U2
5954- # ((a_diff and not D2) or
5955- # (a_int and not C2) or
5956- # (a1 and not C2 and not D2)) and not U2
5905+ # If subtype, a_diff is none and a_union is a2:
59575906 #
5958- # Now, we know that a1 is a_diff or a_int, which means
5959- # (a1 and not C2 and not D2) is a subset of the other two
5960- # expressions, so we end up with:
5907+ # ((U1 and not a2) or (D1 and not D2)) and not U2 and not D2
59615908 #
5962- # ((a_diff and not D2) or (a_int and not C2)) and not U2
5963- #
5964- defp bdd_difference ( bdd_leaf ( _ , _ ) = bdd1 , bdd2 , leaf_compare ) when is_tuple ( bdd2 ) do
5909+ defp bdd_difference ( bdd1 , bdd2 , leaf_compare ) when is_tuple ( bdd1 ) and is_tuple ( bdd2 ) do
5910+ { a1 , c1 , u1 , d1 } = bdd_expand ( bdd1 )
59655911 { a2 , c2 , u2 , d2 } = bdd_expand ( bdd2 )
5966- type = if c2 == :bdd_top , do: :none , else: :intersection
59675912
5968- case leaf_compare . ( bdd1 , a2 , type ) do
5969- :disjoint ->
5970- bdd1 |> bdd_difference ( d2 , leaf_compare ) |> bdd_difference ( u2 , leaf_compare )
5913+ cond do
5914+ d1 == :bdd_bot and c1 == :bdd_top ->
5915+ type = if c2 == :bdd_top , do: :none , else: :intersection
59715916
5972- { :one_key_difference , a_diff , a_int } ->
5973- bdd_union (
5974- a_diff |> bdd_difference ( d2 , leaf_compare ) |> bdd_difference ( u2 , leaf_compare ) ,
5975- a_int |> bdd_difference ( c2 , leaf_compare ) |> bdd_difference ( u2 , leaf_compare )
5976- )
5917+ case leaf_compare . ( a1 , a2 , type ) do
5918+ :disjoint ->
5919+ a1
5920+ |> bdd_difference ( d2 , leaf_compare )
5921+ |> bdd_difference ( u2 , leaf_compare )
5922+ |> bdd_union ( bdd_difference ( u1 , bdd2 , leaf_compare ) )
5923+
5924+ :subtype ->
5925+ a1
5926+ |> bdd_difference ( c2 , leaf_compare )
5927+ |> bdd_difference ( u2 , leaf_compare )
5928+ |> bdd_union ( bdd_difference ( u1 , bdd2 , leaf_compare ) )
5929+
5930+ { :one_key_difference , a_diff , a_int } ->
5931+ bdd_union (
5932+ a_diff |> bdd_difference ( d2 , leaf_compare ) |> bdd_difference ( u2 , leaf_compare ) ,
5933+ a_int |> bdd_difference ( c2 , leaf_compare ) |> bdd_difference ( u2 , leaf_compare )
5934+ )
5935+ |> bdd_union ( bdd_difference ( u1 , bdd2 , leaf_compare ) )
59775936
5978- :subtype ->
5979- bdd1 |> bdd_difference ( c2 , leaf_compare ) |> bdd_difference ( u2 , leaf_compare )
5937+ :none ->
5938+ bdd_difference ( bdd1 , bdd2 )
5939+ end
59805940
5981- :none ->
5941+ c2 == :bdd_top ->
5942+ type = if d1 == :bdd_bot , do: :none , else: :union
5943+
5944+ case leaf_compare . ( a1 , a2 , type ) do
5945+ :disjoint ->
5946+ bdd_difference ( u1 , a2 , leaf_compare )
5947+ |> bdd_union ( bdd_difference ( { a1 , c1 , :bdd_bot , d1 } , a2 ) )
5948+ |> bdd_difference ( d2 , leaf_compare )
5949+ |> bdd_difference ( u2 , leaf_compare )
5950+
5951+ :subtype ->
5952+ bdd_union (
5953+ bdd_difference ( u1 , a2 , leaf_compare ) ,
5954+ bdd_difference ( d1 , a2 , leaf_compare )
5955+ )
5956+ |> bdd_difference ( d2 , leaf_compare )
5957+ |> bdd_difference ( u2 , leaf_compare )
5958+
5959+ { :one_key_difference , a_diff , a_union } ->
5960+ bdd_intersection ( a_diff , c1 )
5961+ |> bdd_union ( bdd_difference ( u1 , a2 , leaf_compare ) )
5962+ |> bdd_union ( bdd_difference ( d1 , a_union , leaf_compare ) )
5963+ |> bdd_difference ( d2 , leaf_compare )
5964+ |> bdd_difference ( u2 , leaf_compare )
5965+
5966+ :none ->
5967+ bdd_difference ( bdd1 , bdd2 )
5968+ end
5969+
5970+ true ->
59825971 bdd_difference ( bdd1 , bdd2 )
59835972 end
59845973 end
0 commit comments