123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- from sympy.core.facts import (deduce_alpha_implications,
- apply_beta_to_alpha_route, rules_2prereq, FactRules, FactKB)
- from sympy.core.logic import And, Not
- from sympy.testing.pytest import raises
- T = True
- F = False
- U = None
- def test_deduce_alpha_implications():
- def D(i):
- I = deduce_alpha_implications(i)
- P = rules_2prereq({
- (k, True): {(v, True) for v in S} for k, S in I.items()})
- return I, P
- # transitivity
- I, P = D([('a', 'b'), ('b', 'c')])
- assert I == {'a': {'b', 'c'}, 'b': {'c'}, Not('b'):
- {Not('a')}, Not('c'): {Not('a'), Not('b')}}
- assert P == {'a': {'b', 'c'}, 'b': {'a', 'c'}, 'c': {'a', 'b'}}
- # Duplicate entry
- I, P = D([('a', 'b'), ('b', 'c'), ('b', 'c')])
- assert I == {'a': {'b', 'c'}, 'b': {'c'}, Not('b'): {Not('a')}, Not('c'): {Not('a'), Not('b')}}
- assert P == {'a': {'b', 'c'}, 'b': {'a', 'c'}, 'c': {'a', 'b'}}
- # see if it is tolerant to cycles
- assert D([('a', 'a'), ('a', 'a')]) == ({}, {})
- assert D([('a', 'b'), ('b', 'a')]) == (
- {'a': {'b'}, 'b': {'a'}, Not('a'): {Not('b')}, Not('b'): {Not('a')}},
- {'a': {'b'}, 'b': {'a'}})
- # see if it catches inconsistency
- raises(ValueError, lambda: D([('a', Not('a'))]))
- raises(ValueError, lambda: D([('a', 'b'), ('b', Not('a'))]))
- raises(ValueError, lambda: D([('a', 'b'), ('b', 'c'), ('b', 'na'),
- ('na', Not('a'))]))
- # see if it handles implications with negations
- I, P = D([('a', Not('b')), ('c', 'b')])
- assert I == {'a': {Not('b'), Not('c')}, 'b': {Not('a')}, 'c': {'b', Not('a')}, Not('b'): {Not('c')}}
- assert P == {'a': {'b', 'c'}, 'b': {'a', 'c'}, 'c': {'a', 'b'}}
- I, P = D([(Not('a'), 'b'), ('a', 'c')])
- assert I == {'a': {'c'}, Not('a'): {'b'}, Not('b'): {'a',
- 'c'}, Not('c'): {Not('a'), 'b'},}
- assert P == {'a': {'b', 'c'}, 'b': {'a', 'c'}, 'c': {'a', 'b'}}
- # Long deductions
- I, P = D([('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'e')])
- assert I == {'a': {'b', 'c', 'd', 'e'}, 'b': {'c', 'd', 'e'},
- 'c': {'d', 'e'}, 'd': {'e'}, Not('b'): {Not('a')},
- Not('c'): {Not('a'), Not('b')}, Not('d'): {Not('a'), Not('b'),
- Not('c')}, Not('e'): {Not('a'), Not('b'), Not('c'), Not('d')}}
- assert P == {'a': {'b', 'c', 'd', 'e'}, 'b': {'a', 'c', 'd',
- 'e'}, 'c': {'a', 'b', 'd', 'e'}, 'd': {'a', 'b', 'c', 'e'},
- 'e': {'a', 'b', 'c', 'd'}}
- # something related to real-world
- I, P = D([('rat', 'real'), ('int', 'rat')])
- assert I == {'int': {'rat', 'real'}, 'rat': {'real'},
- Not('real'): {Not('rat'), Not('int')}, Not('rat'): {Not('int')}}
- assert P == {'rat': {'int', 'real'}, 'real': {'int', 'rat'},
- 'int': {'rat', 'real'}}
- # TODO move me to appropriate place
- def test_apply_beta_to_alpha_route():
- APPLY = apply_beta_to_alpha_route
- # indicates empty alpha-chain with attached beta-rule #bidx
- def Q(bidx):
- return (set(), [bidx])
- # x -> a &(a,b) -> x -- x -> a
- A = {'x': {'a'}}
- B = [(And('a', 'b'), 'x')]
- assert APPLY(A, B) == {'x': ({'a'}, []), 'a': Q(0), 'b': Q(0)}
- # x -> a &(a,!x) -> b -- x -> a
- A = {'x': {'a'}}
- B = [(And('a', Not('x')), 'b')]
- assert APPLY(A, B) == {'x': ({'a'}, []), Not('x'): Q(0), 'a': Q(0)}
- # x -> a b &(a,b) -> c -- x -> a b c
- A = {'x': {'a', 'b'}}
- B = [(And('a', 'b'), 'c')]
- assert APPLY(A, B) == \
- {'x': ({'a', 'b', 'c'}, []), 'a': Q(0), 'b': Q(0)}
- # x -> a &(a,b) -> y -- x -> a [#0]
- A = {'x': {'a'}}
- B = [(And('a', 'b'), 'y')]
- assert APPLY(A, B) == {'x': ({'a'}, [0]), 'a': Q(0), 'b': Q(0)}
- # x -> a b c &(a,b) -> c -- x -> a b c
- A = {'x': {'a', 'b', 'c'}}
- B = [(And('a', 'b'), 'c')]
- assert APPLY(A, B) == \
- {'x': ({'a', 'b', 'c'}, []), 'a': Q(0), 'b': Q(0)}
- # x -> a b &(a,b,c) -> y -- x -> a b [#0]
- A = {'x': {'a', 'b'}}
- B = [(And('a', 'b', 'c'), 'y')]
- assert APPLY(A, B) == \
- {'x': ({'a', 'b'}, [0]), 'a': Q(0), 'b': Q(0), 'c': Q(0)}
- # x -> a b &(a,b) -> c -- x -> a b c d
- # c -> d c -> d
- A = {'x': {'a', 'b'}, 'c': {'d'}}
- B = [(And('a', 'b'), 'c')]
- assert APPLY(A, B) == {'x': ({'a', 'b', 'c', 'd'}, []),
- 'c': ({'d'}, []), 'a': Q(0), 'b': Q(0)}
- # x -> a b &(a,b) -> c -- x -> a b c d e
- # c -> d &(c,d) -> e c -> d e
- A = {'x': {'a', 'b'}, 'c': {'d'}}
- B = [(And('a', 'b'), 'c'), (And('c', 'd'), 'e')]
- assert APPLY(A, B) == {'x': ({'a', 'b', 'c', 'd', 'e'}, []),
- 'c': ({'d', 'e'}, []), 'a': Q(0), 'b': Q(0), 'd': Q(1)}
- # x -> a b &(a,y) -> z -- x -> a b y z
- # &(a,b) -> y
- A = {'x': {'a', 'b'}}
- B = [(And('a', 'y'), 'z'), (And('a', 'b'), 'y')]
- assert APPLY(A, B) == {'x': ({'a', 'b', 'y', 'z'}, []),
- 'a': (set(), [0, 1]), 'y': Q(0), 'b': Q(1)}
- # x -> a b &(a,!b) -> c -- x -> a b
- A = {'x': {'a', 'b'}}
- B = [(And('a', Not('b')), 'c')]
- assert APPLY(A, B) == \
- {'x': ({'a', 'b'}, []), 'a': Q(0), Not('b'): Q(0)}
- # !x -> !a !b &(!a,b) -> c -- !x -> !a !b
- A = {Not('x'): {Not('a'), Not('b')}}
- B = [(And(Not('a'), 'b'), 'c')]
- assert APPLY(A, B) == \
- {Not('x'): ({Not('a'), Not('b')}, []), Not('a'): Q(0), 'b': Q(0)}
- # x -> a b &(b,c) -> !a -- x -> a b
- A = {'x': {'a', 'b'}}
- B = [(And('b', 'c'), Not('a'))]
- assert APPLY(A, B) == {'x': ({'a', 'b'}, []), 'b': Q(0), 'c': Q(0)}
- # x -> a b &(a, b) -> c -- x -> a b c p
- # c -> p a
- A = {'x': {'a', 'b'}, 'c': {'p', 'a'}}
- B = [(And('a', 'b'), 'c')]
- assert APPLY(A, B) == {'x': ({'a', 'b', 'c', 'p'}, []),
- 'c': ({'p', 'a'}, []), 'a': Q(0), 'b': Q(0)}
- def test_FactRules_parse():
- f = FactRules('a -> b')
- assert f.prereq == {'b': {'a'}, 'a': {'b'}}
- f = FactRules('a -> !b')
- assert f.prereq == {'b': {'a'}, 'a': {'b'}}
- f = FactRules('!a -> b')
- assert f.prereq == {'b': {'a'}, 'a': {'b'}}
- f = FactRules('!a -> !b')
- assert f.prereq == {'b': {'a'}, 'a': {'b'}}
- f = FactRules('!z == nz')
- assert f.prereq == {'z': {'nz'}, 'nz': {'z'}}
- def test_FactRules_parse2():
- raises(ValueError, lambda: FactRules('a -> !a'))
- def test_FactRules_deduce():
- f = FactRules(['a -> b', 'b -> c', 'b -> d', 'c -> e'])
- def D(facts):
- kb = FactKB(f)
- kb.deduce_all_facts(facts)
- return kb
- assert D({'a': T}) == {'a': T, 'b': T, 'c': T, 'd': T, 'e': T}
- assert D({'b': T}) == { 'b': T, 'c': T, 'd': T, 'e': T}
- assert D({'c': T}) == { 'c': T, 'e': T}
- assert D({'d': T}) == { 'd': T }
- assert D({'e': T}) == { 'e': T}
- assert D({'a': F}) == {'a': F }
- assert D({'b': F}) == {'a': F, 'b': F }
- assert D({'c': F}) == {'a': F, 'b': F, 'c': F }
- assert D({'d': F}) == {'a': F, 'b': F, 'd': F }
- assert D({'a': U}) == {'a': U} # XXX ok?
- def test_FactRules_deduce2():
- # pos/neg/zero, but the rules are not sufficient to derive all relations
- f = FactRules(['pos -> !neg', 'pos -> !z'])
- def D(facts):
- kb = FactKB(f)
- kb.deduce_all_facts(facts)
- return kb
- assert D({'pos': T}) == {'pos': T, 'neg': F, 'z': F}
- assert D({'pos': F}) == {'pos': F }
- assert D({'neg': T}) == {'pos': F, 'neg': T }
- assert D({'neg': F}) == { 'neg': F }
- assert D({'z': T}) == {'pos': F, 'z': T}
- assert D({'z': F}) == { 'z': F}
- # pos/neg/zero. rules are sufficient to derive all relations
- f = FactRules(['pos -> !neg', 'neg -> !pos', 'pos -> !z', 'neg -> !z'])
- assert D({'pos': T}) == {'pos': T, 'neg': F, 'z': F}
- assert D({'pos': F}) == {'pos': F }
- assert D({'neg': T}) == {'pos': F, 'neg': T, 'z': F}
- assert D({'neg': F}) == { 'neg': F }
- assert D({'z': T}) == {'pos': F, 'neg': F, 'z': T}
- assert D({'z': F}) == { 'z': F}
- def test_FactRules_deduce_multiple():
- # deduction that involves _several_ starting points
- f = FactRules(['real == pos | npos'])
- def D(facts):
- kb = FactKB(f)
- kb.deduce_all_facts(facts)
- return kb
- assert D({'real': T}) == {'real': T}
- assert D({'real': F}) == {'real': F, 'pos': F, 'npos': F}
- assert D({'pos': T}) == {'real': T, 'pos': T}
- assert D({'npos': T}) == {'real': T, 'npos': T}
- # --- key tests below ---
- assert D({'pos': F, 'npos': F}) == {'real': F, 'pos': F, 'npos': F}
- assert D({'real': T, 'pos': F}) == {'real': T, 'pos': F, 'npos': T}
- assert D({'real': T, 'npos': F}) == {'real': T, 'pos': T, 'npos': F}
- assert D({'pos': T, 'npos': F}) == {'real': T, 'pos': T, 'npos': F}
- assert D({'pos': F, 'npos': T}) == {'real': T, 'pos': F, 'npos': T}
- def test_FactRules_deduce_multiple2():
- f = FactRules(['real == neg | zero | pos'])
- def D(facts):
- kb = FactKB(f)
- kb.deduce_all_facts(facts)
- return kb
- assert D({'real': T}) == {'real': T}
- assert D({'real': F}) == {'real': F, 'neg': F, 'zero': F, 'pos': F}
- assert D({'neg': T}) == {'real': T, 'neg': T}
- assert D({'zero': T}) == {'real': T, 'zero': T}
- assert D({'pos': T}) == {'real': T, 'pos': T}
- # --- key tests below ---
- assert D({'neg': F, 'zero': F, 'pos': F}) == {'real': F, 'neg': F,
- 'zero': F, 'pos': F}
- assert D({'real': T, 'neg': F}) == {'real': T, 'neg': F}
- assert D({'real': T, 'zero': F}) == {'real': T, 'zero': F}
- assert D({'real': T, 'pos': F}) == {'real': T, 'pos': F}
- assert D({'real': T, 'zero': F, 'pos': F}) == {'real': T,
- 'neg': T, 'zero': F, 'pos': F}
- assert D({'real': T, 'neg': F, 'pos': F}) == {'real': T,
- 'neg': F, 'zero': T, 'pos': F}
- assert D({'real': T, 'neg': F, 'zero': F }) == {'real': T,
- 'neg': F, 'zero': F, 'pos': T}
- assert D({'neg': T, 'zero': F, 'pos': F}) == {'real': T, 'neg': T,
- 'zero': F, 'pos': F}
- assert D({'neg': F, 'zero': T, 'pos': F}) == {'real': T, 'neg': F,
- 'zero': T, 'pos': F}
- assert D({'neg': F, 'zero': F, 'pos': T}) == {'real': T, 'neg': F,
- 'zero': F, 'pos': T}
- def test_FactRules_deduce_base():
- # deduction that starts from base
- f = FactRules(['real == neg | zero | pos',
- 'neg -> real & !zero & !pos',
- 'pos -> real & !zero & !neg'])
- base = FactKB(f)
- base.deduce_all_facts({'real': T, 'neg': F})
- assert base == {'real': T, 'neg': F}
- base.deduce_all_facts({'zero': F})
- assert base == {'real': T, 'neg': F, 'zero': F, 'pos': T}
- def test_FactRules_deduce_staticext():
- # verify that static beta-extensions deduction takes place
- f = FactRules(['real == neg | zero | pos',
- 'neg -> real & !zero & !pos',
- 'pos -> real & !zero & !neg',
- 'nneg == real & !neg',
- 'npos == real & !pos'])
- assert ('npos', True) in f.full_implications[('neg', True)]
- assert ('nneg', True) in f.full_implications[('pos', True)]
- assert ('nneg', True) in f.full_implications[('zero', True)]
- assert ('npos', True) in f.full_implications[('zero', True)]
|