chceckpoint
This commit is contained in:
parent
bb08fbe078
commit
6a91950d02
386
test.exs
386
test.exs
@ -89,6 +89,10 @@ defmodule Tdd do
|
|||||||
_otherwise, acc_set -> acc_set
|
_otherwise, acc_set -> acc_set
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
IO.inspect({assumptions_map, primary_true_predicates, MapSet.size(primary_true_predicates)},
|
||||||
|
label: "CheckConsistency"
|
||||||
|
)
|
||||||
|
|
||||||
if MapSet.size(primary_true_predicates) > 1 do
|
if MapSet.size(primary_true_predicates) > 1 do
|
||||||
:contradiction
|
:contradiction
|
||||||
else
|
else
|
||||||
@ -114,6 +118,8 @@ defmodule Tdd do
|
|||||||
|
|
||||||
check_assumptions_consistency(assumptions_map) == :contradiction ->
|
check_assumptions_consistency(assumptions_map) == :contradiction ->
|
||||||
# Path is semantically impossible
|
# Path is semantically impossible
|
||||||
|
# Important
|
||||||
|
IO.inspect({tdd_id, assumptions_map}, label: "SimplifyContradiction")
|
||||||
update_state(%{op_cache: Map.put(state.op_cache, cache_key, @false_node_id)})
|
update_state(%{op_cache: Map.put(state.op_cache, cache_key, @false_node_id)})
|
||||||
@false_node_id
|
@false_node_id
|
||||||
|
|
||||||
@ -144,6 +150,7 @@ defmodule Tdd do
|
|||||||
make_node_raw(var, simplified_y, simplified_n, simplified_d)
|
make_node_raw(var, simplified_y, simplified_n, simplified_d)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
IO.inspect({tdd_id, assumptions_map, result_id}, label: "SimplifyExit")
|
||||||
update_state(%{op_cache: Map.put(state.op_cache, cache_key, result_id)})
|
update_state(%{op_cache: Map.put(state.op_cache, cache_key, result_id)})
|
||||||
result_id
|
result_id
|
||||||
end
|
end
|
||||||
@ -402,31 +409,6 @@ tdd_empty_tuple = Tdd.type_empty_tuple()
|
|||||||
tdd_any = Tdd.type_any()
|
tdd_any = Tdd.type_any()
|
||||||
tdd_none = Tdd.type_none()
|
tdd_none = Tdd.type_none()
|
||||||
|
|
||||||
IO.puts("\n--- TDD for :foo ---")
|
|
||||||
Tdd.print_tdd(tdd_foo)
|
|
||||||
|
|
||||||
IO.puts("\n--- TDD for not :foo ---")
|
|
||||||
Tdd.print_tdd(Tdd.negate(tdd_foo))
|
|
||||||
|
|
||||||
IO.puts("\n--- TDD for atom ---")
|
|
||||||
Tdd.print_tdd(tdd_atom)
|
|
||||||
|
|
||||||
IO.puts("\n--- TDD for not atom ---")
|
|
||||||
# Expected: make_node(@v_is_atom, @false_node_id, @true_node_id, @true_node_id)
|
|
||||||
# This represents "anything that is not an atom". The DC branch becomes true because if
|
|
||||||
# "is_atom" test is irrelevant for "not atom", it means it's part of "not atom".
|
|
||||||
Tdd.print_tdd(Tdd.negate(tdd_atom))
|
|
||||||
|
|
||||||
IO.puts("\n--- TDD for :foo and :bar (should be none) ---")
|
|
||||||
tdd_foo_and_bar = Tdd.intersect(tdd_foo, tdd_bar)
|
|
||||||
# Expected ID 0: :false_terminal
|
|
||||||
Tdd.print_tdd(tdd_foo_and_bar)
|
|
||||||
|
|
||||||
IO.puts("\n--- TDD for :foo and atom (should be :foo) ---")
|
|
||||||
tdd_foo_and_atom = Tdd.intersect(tdd_foo, tdd_atom)
|
|
||||||
# Expected to be structurally identical to tdd_foo
|
|
||||||
Tdd.print_tdd(tdd_foo_and_atom)
|
|
||||||
|
|
||||||
test = fn name, expected, result ->
|
test = fn name, expected, result ->
|
||||||
current_failures = Process.get(:test_failures, [])
|
current_failures = Process.get(:test_failures, [])
|
||||||
|
|
||||||
@ -450,176 +432,210 @@ tdd_tuple_s2 = Tdd.type_tuple_sized_any(2)
|
|||||||
tdd_any = Tdd.type_any()
|
tdd_any = Tdd.type_any()
|
||||||
tdd_none = Tdd.type_none()
|
tdd_none = Tdd.type_none()
|
||||||
|
|
||||||
IO.puts("\n--- Basic Subtyping Tests ---")
|
test_all = fn ->
|
||||||
test.(":foo <: atom", true, Tdd.is_subtype(tdd_foo, tdd_atom))
|
IO.puts("\n--- TDD for :foo ---")
|
||||||
test.("atom <: :foo", false, Tdd.is_subtype(tdd_atom, tdd_foo))
|
Tdd.print_tdd(tdd_foo)
|
||||||
test.(":foo <: :bar", false, Tdd.is_subtype(tdd_foo, tdd_bar))
|
|
||||||
test.(":foo <: :foo", true, Tdd.is_subtype(tdd_foo, tdd_foo))
|
|
||||||
test.("{} <: tuple", true, Tdd.is_subtype(tdd_empty_tuple, tdd_tuple))
|
|
||||||
test.("tuple <: {}", false, Tdd.is_subtype(tdd_tuple, tdd_empty_tuple))
|
|
||||||
test.(":foo <: {}", false, Tdd.is_subtype(tdd_foo, tdd_empty_tuple))
|
|
||||||
test.("tuple_size_2 <: tuple", true, Tdd.is_subtype(tdd_tuple_s2, tdd_tuple))
|
|
||||||
test.("tuple <: tuple_size_2", false, Tdd.is_subtype(tdd_tuple, tdd_tuple_s2))
|
|
||||||
test.("tuple_size_2 <: {}", false, Tdd.is_subtype(tdd_tuple_s2, tdd_empty_tuple))
|
|
||||||
|
|
||||||
IO.puts("\n--- Any/None Subtyping Tests ---")
|
IO.puts("\n--- TDD for not :foo ---")
|
||||||
test.("any <: :foo", false, Tdd.is_subtype(tdd_any, tdd_foo))
|
Tdd.print_tdd(Tdd.negate(tdd_foo))
|
||||||
test.(":foo <: any", true, Tdd.is_subtype(tdd_foo, tdd_any))
|
|
||||||
test.("none <: :foo", true, Tdd.is_subtype(tdd_none, tdd_foo))
|
|
||||||
test.(":foo <: none", false, Tdd.is_subtype(tdd_foo, tdd_none))
|
|
||||||
test.("none <: any", true, Tdd.is_subtype(tdd_none, tdd_any))
|
|
||||||
test.("any <: none", false, Tdd.is_subtype(tdd_any, tdd_none))
|
|
||||||
test.("any <: any", true, Tdd.is_subtype(tdd_any, tdd_any))
|
|
||||||
test.("none <: none", true, Tdd.is_subtype(tdd_none, tdd_none))
|
|
||||||
|
|
||||||
IO.puts("\n--- Union related Subtyping ---")
|
IO.puts("\n--- TDD for atom ---")
|
||||||
tdd_foo_or_bar = Tdd.sum(tdd_foo, tdd_bar)
|
Tdd.print_tdd(tdd_atom)
|
||||||
tdd_foo_or_bar_or_baz = Tdd.sum(tdd_foo_or_bar, tdd_baz)
|
|
||||||
|
|
||||||
test.(":foo <: (:foo | :bar)", true, Tdd.is_subtype(tdd_foo, tdd_foo_or_bar))
|
IO.puts("\n--- TDD for not atom ---")
|
||||||
test.(":baz <: (:foo | :bar)", false, Tdd.is_subtype(tdd_baz, tdd_foo_or_bar))
|
# Expected: make_node(@v_is_atom, @false_node_id, @true_node_id, @true_node_id)
|
||||||
test.("(:foo | :bar) <: atom", true, Tdd.is_subtype(tdd_foo_or_bar, tdd_atom))
|
# This represents "anything that is not an atom". The DC branch becomes true because if
|
||||||
test.("atom <: (:foo | :bar)", false, Tdd.is_subtype(tdd_atom, tdd_foo_or_bar))
|
# "is_atom" test is irrelevant for "not atom", it means it's part of "not atom".
|
||||||
|
Tdd.print_tdd(Tdd.negate(tdd_atom))
|
||||||
|
|
||||||
test.(
|
IO.puts("\n--- TDD for :foo and :bar (should be none) ---")
|
||||||
"(:foo | :bar) <: (:foo | :bar | :baz)",
|
tdd_foo_and_bar = Tdd.intersect(tdd_foo, tdd_bar)
|
||||||
true,
|
# Expected ID 0: :false_terminal
|
||||||
Tdd.is_subtype(tdd_foo_or_bar, tdd_foo_or_bar_or_baz)
|
Tdd.print_tdd(tdd_foo_and_bar)
|
||||||
)
|
|
||||||
|
|
||||||
test.(
|
IO.puts("\n--- TDD for :foo and atom (should be :foo) ---")
|
||||||
"(:foo | :bar | :baz) <: (:foo | :bar)",
|
tdd_foo_and_atom = Tdd.intersect(tdd_foo, tdd_atom)
|
||||||
false,
|
# Expected to be structurally identical to tdd_foo
|
||||||
Tdd.is_subtype(tdd_foo_or_bar_or_baz, tdd_foo_or_bar)
|
Tdd.print_tdd(tdd_foo_and_atom)
|
||||||
)
|
IO.puts("\n--- Basic Subtyping Tests ---")
|
||||||
|
test.(":foo <: atom", true, Tdd.is_subtype(tdd_foo, tdd_atom))
|
||||||
|
test.("atom <: :foo", false, Tdd.is_subtype(tdd_atom, tdd_foo))
|
||||||
|
test.(":foo <: :bar", false, Tdd.is_subtype(tdd_foo, tdd_bar))
|
||||||
|
test.(":foo <: :foo", true, Tdd.is_subtype(tdd_foo, tdd_foo))
|
||||||
|
test.("{} <: tuple", true, Tdd.is_subtype(tdd_empty_tuple, tdd_tuple))
|
||||||
|
test.("tuple <: {}", false, Tdd.is_subtype(tdd_tuple, tdd_empty_tuple))
|
||||||
|
test.(":foo <: {}", false, Tdd.is_subtype(tdd_foo, tdd_empty_tuple))
|
||||||
|
test.("tuple_size_2 <: tuple", true, Tdd.is_subtype(tdd_tuple_s2, tdd_tuple))
|
||||||
|
test.("tuple <: tuple_size_2", false, Tdd.is_subtype(tdd_tuple, tdd_tuple_s2))
|
||||||
|
test.("tuple_size_2 <: {}", false, Tdd.is_subtype(tdd_tuple_s2, tdd_empty_tuple))
|
||||||
|
|
||||||
# Test against a non-member of the union
|
IO.puts("\n--- Any/None Subtyping Tests ---")
|
||||||
test.("(:foo | :bar) <: :baz", false, Tdd.is_subtype(tdd_foo_or_bar, tdd_baz))
|
test.("any <: :foo", false, Tdd.is_subtype(tdd_any, tdd_foo))
|
||||||
|
test.(":foo <: any", true, Tdd.is_subtype(tdd_foo, tdd_any))
|
||||||
|
test.("none <: :foo", true, Tdd.is_subtype(tdd_none, tdd_foo))
|
||||||
|
test.(":foo <: none", false, Tdd.is_subtype(tdd_foo, tdd_none))
|
||||||
|
test.("none <: any", true, Tdd.is_subtype(tdd_none, tdd_any))
|
||||||
|
test.("any <: none", false, Tdd.is_subtype(tdd_any, tdd_none))
|
||||||
|
test.("any <: any", true, Tdd.is_subtype(tdd_any, tdd_any))
|
||||||
|
test.("none <: none", true, Tdd.is_subtype(tdd_none, tdd_none))
|
||||||
|
|
||||||
|
IO.puts("\n--- Union related Subtyping ---")
|
||||||
|
tdd_foo_or_bar = Tdd.sum(tdd_foo, tdd_bar)
|
||||||
|
tdd_foo_or_bar_or_baz = Tdd.sum(tdd_foo_or_bar, tdd_baz)
|
||||||
|
|
||||||
|
test.(":foo <: (:foo | :bar)", true, Tdd.is_subtype(tdd_foo, tdd_foo_or_bar))
|
||||||
|
test.(":baz <: (:foo | :bar)", false, Tdd.is_subtype(tdd_baz, tdd_foo_or_bar))
|
||||||
|
test.("(:foo | :bar) <: atom", true, Tdd.is_subtype(tdd_foo_or_bar, tdd_atom))
|
||||||
|
test.("atom <: (:foo | :bar)", false, Tdd.is_subtype(tdd_atom, tdd_foo_or_bar))
|
||||||
|
|
||||||
|
test.(
|
||||||
|
"(:foo | :bar) <: (:foo | :bar | :baz)",
|
||||||
|
true,
|
||||||
|
Tdd.is_subtype(tdd_foo_or_bar, tdd_foo_or_bar_or_baz)
|
||||||
|
)
|
||||||
|
|
||||||
|
test.(
|
||||||
|
"(:foo | :bar | :baz) <: (:foo | :bar)",
|
||||||
|
false,
|
||||||
|
Tdd.is_subtype(tdd_foo_or_bar_or_baz, tdd_foo_or_bar)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test against a non-member of the union
|
||||||
|
test.("(:foo | :bar) <: :baz", false, Tdd.is_subtype(tdd_foo_or_bar, tdd_baz))
|
||||||
|
|
||||||
|
IO.puts("\n--- Intersection related Subtyping ---")
|
||||||
|
# Should be equivalent to tdd_foo
|
||||||
|
tdd_atom_and_foo = Tdd.intersect(tdd_atom, tdd_foo)
|
||||||
|
# Should be tdd_none
|
||||||
|
tdd_atom_and_tuple = Tdd.intersect(tdd_atom, tdd_tuple)
|
||||||
|
|
||||||
|
test.("(atom & :foo) <: :foo", true, Tdd.is_subtype(tdd_atom_and_foo, tdd_foo))
|
||||||
|
test.(":foo <: (atom & :foo)", true, Tdd.is_subtype(tdd_foo, tdd_atom_and_foo))
|
||||||
|
test.("(atom & tuple) <: none", true, Tdd.is_subtype(tdd_atom_and_tuple, tdd_none))
|
||||||
|
test.("none <: (atom & tuple)", true, Tdd.is_subtype(tdd_none, tdd_atom_and_tuple))
|
||||||
|
test.("(atom & :foo) <: :bar", false, Tdd.is_subtype(tdd_atom_and_foo, tdd_bar))
|
||||||
|
# An intersection is a subtype of its components
|
||||||
|
test.("(atom & :foo) <: atom", true, Tdd.is_subtype(tdd_atom_and_foo, tdd_atom))
|
||||||
|
# (none <: atom)
|
||||||
|
test.("(atom & tuple) <: atom", true, Tdd.is_subtype(tdd_atom_and_tuple, tdd_atom))
|
||||||
|
# (none <: tuple)
|
||||||
|
test.("(atom & tuple) <: tuple", true, Tdd.is_subtype(tdd_atom_and_tuple, tdd_tuple))
|
||||||
|
|
||||||
|
IO.puts("\n--- Negation related Subtyping (Contrapositives) ---")
|
||||||
|
# Reminder: ¬A <: ¬B is equivalent to B <: A (contrapositive)
|
||||||
|
|
||||||
|
# Test 1: ¬atom <: ¬:foo (Equivalent to :foo <: atom, which is true)
|
||||||
|
test.("¬atom <: ¬:foo", true, Tdd.is_subtype(Tdd.negate(tdd_atom), Tdd.negate(tdd_foo)))
|
||||||
|
|
||||||
|
# Test 2: ¬:foo <: ¬atom (Equivalent to atom <: :foo, which is false)
|
||||||
|
test.("¬:foo <: ¬atom", false, Tdd.is_subtype(Tdd.negate(tdd_foo), Tdd.negate(tdd_atom)))
|
||||||
|
|
||||||
|
# Double negation
|
||||||
|
test.("¬(¬:foo) <: :foo", true, Tdd.is_subtype(Tdd.negate(Tdd.negate(tdd_foo)), tdd_foo))
|
||||||
|
test.(":foo <: ¬(¬:foo)", true, Tdd.is_subtype(tdd_foo, Tdd.negate(Tdd.negate(tdd_foo))))
|
||||||
|
|
||||||
|
# Disjoint types
|
||||||
|
test.("atom <: ¬tuple", true, Tdd.is_subtype(tdd_atom, Tdd.negate(tdd_tuple)))
|
||||||
|
test.("tuple <: ¬atom", true, Tdd.is_subtype(tdd_tuple, Tdd.negate(tdd_atom)))
|
||||||
|
test.(":foo <: ¬{}", true, Tdd.is_subtype(tdd_foo, Tdd.negate(tdd_empty_tuple)))
|
||||||
|
|
||||||
|
IO.puts("\n--- Mixed Types & Complex Subtyping ---")
|
||||||
|
tdd_atom_or_tuple = Tdd.sum(tdd_atom, tdd_tuple)
|
||||||
|
tdd_foo_or_empty_tuple = Tdd.sum(tdd_foo, tdd_empty_tuple)
|
||||||
|
|
||||||
|
test.(
|
||||||
|
"(:foo | {}) <: (atom | tuple)",
|
||||||
|
true,
|
||||||
|
Tdd.is_subtype(tdd_foo_or_empty_tuple, tdd_atom_or_tuple)
|
||||||
|
)
|
||||||
|
|
||||||
|
test.(
|
||||||
|
"(atom | tuple) <: (:foo | {})",
|
||||||
|
false,
|
||||||
|
Tdd.is_subtype(tdd_atom_or_tuple, tdd_foo_or_empty_tuple)
|
||||||
|
)
|
||||||
|
|
||||||
|
test.(":foo <: (atom | tuple)", true, Tdd.is_subtype(tdd_foo, tdd_atom_or_tuple))
|
||||||
|
test.("{} <: (atom | tuple)", true, Tdd.is_subtype(tdd_empty_tuple, tdd_atom_or_tuple))
|
||||||
|
|
||||||
|
# De Morgan's Law illustration (A | B = ¬(¬A & ¬B))
|
||||||
|
# (:foo | :bar) <: ¬(¬:foo & ¬:bar)
|
||||||
|
tdd_not_foo_and_not_bar = Tdd.intersect(Tdd.negate(tdd_foo), Tdd.negate(tdd_bar))
|
||||||
|
|
||||||
|
test.(
|
||||||
|
"(:foo | :bar) <: ¬(¬:foo & ¬:bar)",
|
||||||
|
true,
|
||||||
|
Tdd.is_subtype(tdd_foo_or_bar, Tdd.negate(tdd_not_foo_and_not_bar))
|
||||||
|
)
|
||||||
|
|
||||||
|
test.(
|
||||||
|
"¬(¬:foo & ¬:bar) <: (:foo | :bar)",
|
||||||
|
true,
|
||||||
|
Tdd.is_subtype(Tdd.negate(tdd_not_foo_and_not_bar), tdd_foo_or_bar)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Type difference: atom - :foo (represented as atom & ¬:foo)
|
||||||
|
tdd_atom_minus_foo = Tdd.intersect(tdd_atom, Tdd.negate(tdd_foo))
|
||||||
|
test.("(atom - :foo) <: atom", true, Tdd.is_subtype(tdd_atom_minus_foo, tdd_atom))
|
||||||
|
test.("(atom - :foo) <: :foo", false, Tdd.is_subtype(tdd_atom_minus_foo, tdd_foo))
|
||||||
|
# True if :bar is in (atom - :foo)
|
||||||
|
test.("(atom - :foo) <: :bar", true, Tdd.is_subtype(tdd_atom_minus_foo, tdd_bar))
|
||||||
|
test.(":bar <: (atom - :foo)", true, Tdd.is_subtype(tdd_bar, tdd_atom_minus_foo))
|
||||||
|
|
||||||
|
# (atom - :foo) | :foo should be atom
|
||||||
|
tdd_recombined_atom = Tdd.sum(tdd_atom_minus_foo, tdd_foo)
|
||||||
|
test.("((atom - :foo) | :foo) <: atom", true, Tdd.is_subtype(tdd_recombined_atom, tdd_atom))
|
||||||
|
test.("atom <: ((atom - :foo) | :foo)", true, Tdd.is_subtype(tdd_atom, tdd_recombined_atom))
|
||||||
|
|
||||||
|
# (atom | {}) & (tuple | :foo) must be (:foo | {})
|
||||||
|
# Represents `atom() | {}`
|
||||||
|
tdd_atom_or_empty = Tdd.sum(tdd_atom, tdd_empty_tuple)
|
||||||
|
# Represents `tuple() | :foo`
|
||||||
|
tdd_tuple_or_foo = Tdd.sum(tdd_tuple, tdd_foo)
|
||||||
|
intersected_complex = Tdd.intersect(tdd_atom_or_empty, tdd_tuple_or_foo)
|
||||||
|
# Expected result for intersected_complex is tdd_foo_or_empty_tuple
|
||||||
|
|
||||||
|
test.(
|
||||||
|
"(atom | {}) & (tuple | :foo) <: (:foo | {})",
|
||||||
|
true,
|
||||||
|
Tdd.is_subtype(intersected_complex, tdd_foo_or_empty_tuple)
|
||||||
|
)
|
||||||
|
|
||||||
|
test.(
|
||||||
|
"(:foo | {}) <: (atom | {}) & (tuple | :foo)",
|
||||||
|
true,
|
||||||
|
Tdd.is_subtype(tdd_foo_or_empty_tuple, intersected_complex)
|
||||||
|
)
|
||||||
|
|
||||||
|
# {} | tuple_size_2 should be a subtype of tuple
|
||||||
|
tdd_empty_or_s2 = Tdd.sum(tdd_empty_tuple, tdd_tuple_s2)
|
||||||
|
test.("({} | tuple_size_2) <: tuple", true, Tdd.is_subtype(tdd_empty_or_s2, tdd_tuple))
|
||||||
|
|
||||||
|
test.(
|
||||||
|
"({} | tuple_size_2) <: ({} | tuple_size_2)",
|
||||||
|
true,
|
||||||
|
Tdd.is_subtype(tdd_empty_or_s2, tdd_empty_or_s2)
|
||||||
|
)
|
||||||
|
|
||||||
|
test.(
|
||||||
|
"({} | tuple_size_2) <: tuple_size_2",
|
||||||
|
false,
|
||||||
|
Tdd.is_subtype(tdd_empty_or_s2, tdd_tuple_s2)
|
||||||
|
)
|
||||||
|
|
||||||
|
IO.puts("\n--- TDD structure for (atom - :foo) ---")
|
||||||
|
Tdd.print_tdd(tdd_atom_minus_foo)
|
||||||
|
IO.puts("\n--- TDD structure for ((atom - :foo) | :foo) which should be 'atom' ---")
|
||||||
|
Tdd.print_tdd(tdd_recombined_atom)
|
||||||
|
IO.puts("\n--- TDD structure for 'atom' for comparison ---")
|
||||||
|
Tdd.print_tdd(tdd_atom)
|
||||||
|
|
||||||
|
IO.inspect(Process.get(:test_failures, []))
|
||||||
|
end
|
||||||
|
|
||||||
IO.puts("\n--- Intersection related Subtyping ---")
|
|
||||||
# Should be equivalent to tdd_foo
|
|
||||||
tdd_atom_and_foo = Tdd.intersect(tdd_atom, tdd_foo)
|
|
||||||
# Should be tdd_none
|
# Should be tdd_none
|
||||||
tdd_atom_and_tuple = Tdd.intersect(tdd_atom, tdd_tuple)
|
tdd_atom_and_tuple = Tdd.intersect(tdd_atom, tdd_tuple)
|
||||||
|
|
||||||
test.("(atom & :foo) <: :foo", true, Tdd.is_subtype(tdd_atom_and_foo, tdd_foo))
|
|
||||||
test.(":foo <: (atom & :foo)", true, Tdd.is_subtype(tdd_foo, tdd_atom_and_foo))
|
|
||||||
test.("(atom & tuple) <: none", true, Tdd.is_subtype(tdd_atom_and_tuple, tdd_none))
|
test.("(atom & tuple) <: none", true, Tdd.is_subtype(tdd_atom_and_tuple, tdd_none))
|
||||||
test.("none <: (atom & tuple)", true, Tdd.is_subtype(tdd_none, tdd_atom_and_tuple))
|
|
||||||
test.("(atom & :foo) <: :bar", false, Tdd.is_subtype(tdd_atom_and_foo, tdd_bar))
|
|
||||||
# An intersection is a subtype of its components
|
|
||||||
test.("(atom & :foo) <: atom", true, Tdd.is_subtype(tdd_atom_and_foo, tdd_atom))
|
|
||||||
# (none <: atom)
|
|
||||||
test.("(atom & tuple) <: atom", true, Tdd.is_subtype(tdd_atom_and_tuple, tdd_atom))
|
|
||||||
# (none <: tuple)
|
|
||||||
test.("(atom & tuple) <: tuple", true, Tdd.is_subtype(tdd_atom_and_tuple, tdd_tuple))
|
|
||||||
|
|
||||||
IO.puts("\n--- Negation related Subtyping (Contrapositives) ---")
|
|
||||||
# Reminder: ¬A <: ¬B is equivalent to B <: A (contrapositive)
|
|
||||||
|
|
||||||
# Test 1: ¬atom <: ¬:foo (Equivalent to :foo <: atom, which is true)
|
|
||||||
test.("¬atom <: ¬:foo", true, Tdd.is_subtype(Tdd.negate(tdd_atom), Tdd.negate(tdd_foo)))
|
|
||||||
|
|
||||||
# Test 2: ¬:foo <: ¬atom (Equivalent to atom <: :foo, which is false)
|
|
||||||
test.("¬:foo <: ¬atom", false, Tdd.is_subtype(Tdd.negate(tdd_foo), Tdd.negate(tdd_atom)))
|
|
||||||
|
|
||||||
# Double negation
|
|
||||||
test.("¬(¬:foo) <: :foo", true, Tdd.is_subtype(Tdd.negate(Tdd.negate(tdd_foo)), tdd_foo))
|
|
||||||
test.(":foo <: ¬(¬:foo)", true, Tdd.is_subtype(tdd_foo, Tdd.negate(Tdd.negate(tdd_foo))))
|
|
||||||
|
|
||||||
# Disjoint types
|
|
||||||
test.("atom <: ¬tuple", true, Tdd.is_subtype(tdd_atom, Tdd.negate(tdd_tuple)))
|
|
||||||
test.("tuple <: ¬atom", true, Tdd.is_subtype(tdd_tuple, Tdd.negate(tdd_atom)))
|
|
||||||
test.(":foo <: ¬{}", true, Tdd.is_subtype(tdd_foo, Tdd.negate(tdd_empty_tuple)))
|
|
||||||
|
|
||||||
IO.puts("\n--- Mixed Types & Complex Subtyping ---")
|
|
||||||
tdd_atom_or_tuple = Tdd.sum(tdd_atom, tdd_tuple)
|
|
||||||
tdd_foo_or_empty_tuple = Tdd.sum(tdd_foo, tdd_empty_tuple)
|
|
||||||
|
|
||||||
test.(
|
|
||||||
"(:foo | {}) <: (atom | tuple)",
|
|
||||||
true,
|
|
||||||
Tdd.is_subtype(tdd_foo_or_empty_tuple, tdd_atom_or_tuple)
|
|
||||||
)
|
|
||||||
|
|
||||||
test.(
|
|
||||||
"(atom | tuple) <: (:foo | {})",
|
|
||||||
false,
|
|
||||||
Tdd.is_subtype(tdd_atom_or_tuple, tdd_foo_or_empty_tuple)
|
|
||||||
)
|
|
||||||
|
|
||||||
test.(":foo <: (atom | tuple)", true, Tdd.is_subtype(tdd_foo, tdd_atom_or_tuple))
|
|
||||||
test.("{} <: (atom | tuple)", true, Tdd.is_subtype(tdd_empty_tuple, tdd_atom_or_tuple))
|
|
||||||
|
|
||||||
# De Morgan's Law illustration (A | B = ¬(¬A & ¬B))
|
|
||||||
# (:foo | :bar) <: ¬(¬:foo & ¬:bar)
|
|
||||||
tdd_not_foo_and_not_bar = Tdd.intersect(Tdd.negate(tdd_foo), Tdd.negate(tdd_bar))
|
|
||||||
|
|
||||||
test.(
|
|
||||||
"(:foo | :bar) <: ¬(¬:foo & ¬:bar)",
|
|
||||||
true,
|
|
||||||
Tdd.is_subtype(tdd_foo_or_bar, Tdd.negate(tdd_not_foo_and_not_bar))
|
|
||||||
)
|
|
||||||
|
|
||||||
test.(
|
|
||||||
"¬(¬:foo & ¬:bar) <: (:foo | :bar)",
|
|
||||||
true,
|
|
||||||
Tdd.is_subtype(Tdd.negate(tdd_not_foo_and_not_bar), tdd_foo_or_bar)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Type difference: atom - :foo (represented as atom & ¬:foo)
|
|
||||||
tdd_atom_minus_foo = Tdd.intersect(tdd_atom, Tdd.negate(tdd_foo))
|
|
||||||
test.("(atom - :foo) <: atom", true, Tdd.is_subtype(tdd_atom_minus_foo, tdd_atom))
|
|
||||||
test.("(atom - :foo) <: :foo", false, Tdd.is_subtype(tdd_atom_minus_foo, tdd_foo))
|
|
||||||
# True if :bar is in (atom - :foo)
|
|
||||||
test.("(atom - :foo) <: :bar", true, Tdd.is_subtype(tdd_atom_minus_foo, tdd_bar))
|
|
||||||
test.(":bar <: (atom - :foo)", true, Tdd.is_subtype(tdd_bar, tdd_atom_minus_foo))
|
|
||||||
|
|
||||||
# (atom - :foo) | :foo should be atom
|
|
||||||
tdd_recombined_atom = Tdd.sum(tdd_atom_minus_foo, tdd_foo)
|
|
||||||
test.("((atom - :foo) | :foo) <: atom", true, Tdd.is_subtype(tdd_recombined_atom, tdd_atom))
|
|
||||||
test.("atom <: ((atom - :foo) | :foo)", true, Tdd.is_subtype(tdd_atom, tdd_recombined_atom))
|
|
||||||
|
|
||||||
# (atom | {}) & (tuple | :foo) must be (:foo | {})
|
|
||||||
# Represents `atom() | {}`
|
|
||||||
tdd_atom_or_empty = Tdd.sum(tdd_atom, tdd_empty_tuple)
|
|
||||||
# Represents `tuple() | :foo`
|
|
||||||
tdd_tuple_or_foo = Tdd.sum(tdd_tuple, tdd_foo)
|
|
||||||
intersected_complex = Tdd.intersect(tdd_atom_or_empty, tdd_tuple_or_foo)
|
|
||||||
# Expected result for intersected_complex is tdd_foo_or_empty_tuple
|
|
||||||
|
|
||||||
test.(
|
|
||||||
"(atom | {}) & (tuple | :foo) <: (:foo | {})",
|
|
||||||
true,
|
|
||||||
Tdd.is_subtype(intersected_complex, tdd_foo_or_empty_tuple)
|
|
||||||
)
|
|
||||||
|
|
||||||
test.(
|
|
||||||
"(:foo | {}) <: (atom | {}) & (tuple | :foo)",
|
|
||||||
true,
|
|
||||||
Tdd.is_subtype(tdd_foo_or_empty_tuple, intersected_complex)
|
|
||||||
)
|
|
||||||
|
|
||||||
# {} | tuple_size_2 should be a subtype of tuple
|
|
||||||
tdd_empty_or_s2 = Tdd.sum(tdd_empty_tuple, tdd_tuple_s2)
|
|
||||||
test.("({} | tuple_size_2) <: tuple", true, Tdd.is_subtype(tdd_empty_or_s2, tdd_tuple))
|
|
||||||
|
|
||||||
test.(
|
|
||||||
"({} | tuple_size_2) <: ({} | tuple_size_2)",
|
|
||||||
true,
|
|
||||||
Tdd.is_subtype(tdd_empty_or_s2, tdd_empty_or_s2)
|
|
||||||
)
|
|
||||||
|
|
||||||
test.("({} | tuple_size_2) <: tuple_size_2", false, Tdd.is_subtype(tdd_empty_or_s2, tdd_tuple_s2))
|
|
||||||
|
|
||||||
IO.puts("\n--- TDD structure for (atom - :foo) ---")
|
|
||||||
Tdd.print_tdd(tdd_atom_minus_foo)
|
|
||||||
IO.puts("\n--- TDD structure for ((atom - :foo) | :foo) which should be 'atom' ---")
|
|
||||||
Tdd.print_tdd(tdd_recombined_atom)
|
|
||||||
IO.puts("\n--- TDD structure for 'atom' for comparison ---")
|
|
||||||
Tdd.print_tdd(tdd_atom)
|
|
||||||
|
|
||||||
IO.inspect(Process.get(:test_failures, []))
|
|
||||||
IO.inspect("tdd_atom_and_tuple")
|
IO.inspect("tdd_atom_and_tuple")
|
||||||
Tdd.print_tdd(tdd_atom_and_tuple)
|
Tdd.print_tdd(tdd_atom_and_tuple)
|
||||||
IO.inspect("tdd_none")
|
IO.inspect("tdd_none")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user