def member(E: Term, A_List: Union[SuperSequence, Var]): """ Is E in A_List? """ # If A_List is empty, it can't have a member. So fail. if A_List.is_empty(): return # The following is an implicit 'or'. Either unify E with A_List.head() or call member(E, A_List.tail()). # The first case is easy. # for _ in unify(E, A_List.head( )): # yield yield from unify(E, A_List.head()) # The second case--member(E, A_List.tail())--is trickier. # Since A_List may be an open-ended LinkedList, A_List.tail() may be a Var. # In that case, we must first instantiate A_List.tail() to LinkedList( (Var, Var) ). A_List_Tail = A_List.tail() # Create A_List_New_Tail to be unified with A_List_Tail. # A_List_New_Tail will be A_List_Tail in most cases. # But if isinstance(A_List_Tail, Var), make A_List_New_Tail = LinkedList( (Var( ), Var( )) ). # In either case, unify A_List_Tail with A_List_New_Tail and call member(E, A_List_New_Tail). # An issue is that we can't import LinkedList since that would create an import cycle. # Instead use type(A_List), which will be LinkedList if A_List_Tail is a Var. A_List_New_Tail = type(A_List)( (Var(), Var())) if isinstance(A_List_Tail, Var) else A_List_Tail # If A_List_New_Tail is A_List_Tail, this unify does nothing. for _ in unify(A_List_New_Tail, A_List_Tail): yield from member(E, A_List_New_Tail)
def __add__(self, Other: Union[PySequence, Var]) -> PySequence: Other_EoT = Other.unification_chain_end() # If not, can't append. assert isinstance(Other_EoT, PySequence) Result = Var() for _ in append(self, Other_EoT, Result): Result_EoT = Result.unification_chain_end() # To make the PyCharm type checker happy. assert isinstance(Result_EoT, PySequence) return Result_EoT
def clue_4(self, Students: SuperSequence): """ 4. Erma has a $10,000 larger scholarship than Carrie. This means that Erma comes after the person who comes after Carrie. """ yield from is_contiguous_in( [Student(name='Carrie'), Var(), Student(name='Erma')], Students)
def transversal_yield_lv(sets: List[PyList], so_far: PyList, Answer: Var): print(f'sets/[{", ".join([str(S) for S in sets])}]; so_far_reversed/{reversed(so_far)}') if not sets: yield from unify(reversed(so_far), Answer) else: [S, *Ss] = sets X = Var( ) for _ in member(X, S): for _ in fails(member)(X, so_far): yield from transversal_yield_lv(Ss, PyList([X]) + so_far, Answer)
def transversal_yield_lv(Sets: List[PyList], Partial_Transversal: PyList, Complete_Transversal: Var): print( f'Sets/[{", ".join([str(S) for S in Sets])}]; Partial_Transversal/{Partial_Transversal}' ) if not Sets: yield from unify(Partial_Transversal, Complete_Transversal) else: (S, Ss) = (Sets[0], Sets[1:]) Element = Var() for _ in member(Element, S): for _ in fails(member)(Element, Partial_Transversal): yield from transversal_yield_lv( Ss, Partial_Transversal + PyList([Element]), Complete_Transversal)
def has_contiguous_sublist(self, As: List): """ Can As be unified with a segment of this list? """ # Initially, As is a standard Python list. Make it a LinkedList. As = LinkedList(As) (len_As, len_self) = (len(As), len(self)) if len_As == 0: yield # Succeed once. elif len_As > len_self: return # Fail. else: (Xs, Ys) = n_Vars(2) # Succeed if we can find a way to divide self into Xs and Ys so that As is an initial sublist of Ys. # for _ in forall([lambda: append(Xs, Ys, self), # lambda: append(As, Var( ), Ys) # ]): # yield for _ in append(Xs, Ys, self): yield from append(As, Var(), Ys)
# If is_even_1(i) fails to unify, for _ in is_even_1(i) fails. # It works similarly to an if condition. evens_1 = [i for i in range(5) for _ in is_even_1(i)] print(f'\n1. evens_1: {evens_1}') # => 1. evens_1: [0, 2, 4] # Same as is_even_1 but includes the range generator. def is_even_2(n: int, Res: Var) -> Generator[None, None, None]: for i in range(n): for _ in unify_pairs([ (PyValue(i % 2 == 0), PyValue(True)), (PyValue(i), Res) ]): yield # Can reuse this variable in all examples. # After each example, it is left uninstantiated. Result = Var() # This version uses the function directly as a generator. evens_2 = [Result.get_py_value() for _ in is_even_2(7, Result)] print(f'2. evens_2: {evens_2}') # => 2. evens_2: [0, 2, 4, 6] evens_3 = [] # Here we apply the decorator function explicitly. # bool_yield_wrapper makes it possible to use the generator with .has_more() as a boolean. # The has_more() function, defined in the BoolYIeldWrapper class, both calls next() on # the generator and returns True or False depending on whether next() has succeeded. If # next() succeeds, the next value is unified with Result. The next value is also stored # within the BoolYIeldWrapper object as self.next, and can be retrieved that way. with bool_yield_wrapper(is_even_2)(9, Result) as is_even_gen_3: while is_even_gen_3.has_more( ): evens_3.append(Result.get_py_value())
lambda: unify_pairs([(Xs, LinkedList((XZ_Head, Xs_Tail))), (Zs, LinkedList((XZ_Head, Zs_Tail)))]), lambda: append(Xs_Tail, Ys, Zs_Tail) ]) ]): yield if __name__ == '__main__': print(emptyLinkedList) E = PyValue(3) for _ in member(E, emptyLinkedList): print(f'Error: should not get here.') A = LinkedList((Var(), Var())) A112 = A[4:11:2] A37 = A[3:7] print(f'\nA: {A}\nA[3:7]: {A37}\nA[4:11:2]: {A112}') for _ in unify(A37, LinkedList('ABCD')): print(f'\nA: {A}\nA[3:7]: {A37}\nA[4:11:2]: {A112}') print() print(f'A[:4]: {A[:4]}') A_tail = A.tail() print(f'A.tail()[:3]: {A_tail[:3]}') print(f'A.tail().tail()[:2]: {A.tail().tail()[:2]}') print(f'\nemptyLinkedList: {emptyLinkedList}') Xs = LinkedList([*range(10)])
*Xs.unification_chain_end().args, *Ys.unification_chain_end().args ] yield from unify_sequences(XYs, Zs.args) # for _ in unify_sequences(XYs, Zs.args): # yield if __name__ == '__main__': print(PyTuple((1, 2, 3))) print(PyList([1, 2, 3])) Xs = PyList(['Python']) # list(map(PyValue, range(3))) Ys = PyList([PyValue('Q')]) # [PyValue(i+3) for i in range(3)] Zs = Var() print(f'\nappend({Xs}, {Ys}, {Zs})') for _ in append(Xs, Ys, Zs): print(f'\tXs: {Xs}, Ys: {Ys}, Zs: {Zs}') Xs = Var() Ys = Var() Zs = PyList(list(range(5))) print(f'\nappend({Xs}, {Ys}, {Zs})') for _ in append(Xs, Ys, Zs): print(f'\tXs: {Xs}, Ys: {Ys}, Zs: {Zs}') Xs = Var() Ys = Var()
def clue_4(self, Stdnts): """ Marie has a $10,000 larger scholarship than Lynn. """ yield from is_contiguous_in( [Stdnt(name='Lynn'), Var(), Stdnt(name='Marie')], Stdnts)
def clue_2(self, Stdnts): """ Emmy studies either Math or Bio. """ # Create Major as a local logic variable. Major = Var() for _ in member(Stdnt(name='Emmy', major=Major), Stdnts): yield from member(Major, PyList(['Math', 'Bio']))
nxt_indx = min(var_indxs, key=lambda indx: len(sets[indx])) used_values = PyList( [tnvsl[i] for i in range(len(tnvsl)) if i not in var_indxs]) T_Var = tnvsl[nxt_indx] for _ in member(T_Var, sets[nxt_indx]): for _ in fails(member)(T_Var, used_values): new_sets = [set.discard(T_Var) for set in sets] yield from tnvsl_dfs_gen_lv(new_sets, tnvsl) if __name__ == '__main__': print('\n\n latest') Trace.trace = True print(f'\n{"=" * 15}') (A, B, C) = (Var(), Var(), Var()) Py_Sets = [PySet(set) for set in sets] N = PyValue(6) for _ in tnvsl_dfs_gen_lv(Py_Sets, (A, B, C)): sum_string = ' + '.join(str(i) for i in (A, B, C)) equals = '==' if A + B + C == N else '!=' print(f'{sum_string} {equals} 6') if A + B + C == N: break print(f'{"=" * 15}') # propagate = True # smallest_first = True # def find_transversal_with_sum_n(py_sets: List[PySet], n: PyValue): # (A, B, C) = (Var(), Var(), Var()) # for _ in tnvsl_dfs_gen_lv(py_sets, (A, B, C)): # if A + B + C == n:
yield from unify(Partial_Transversal, Complete_Transversal) else: (S, Ss) = (Sets[0], Sets[1:]) Element = Var() for _ in member(Element, S): for _ in fails(member)(Element, Partial_Transversal): yield from transversal_yield_lv( Ss, Partial_Transversal + PyList([Element]), Complete_Transversal) if __name__ == '__main__': print( f'\n{"-"*75}\ntransversal_yield_lv([[1, 2, 3], [2, 4], [1]], [], Ans)\n' ) Complete_Transversal = Var() for _ in transversal_yield_lv( [PyList([1, 2, 3]), PyList([2, 4]), PyList([1])], PyList([]), Complete_Transversal): print(f'{" "*30} => {Complete_Transversal}') """ --------------------------------------------------------------------------- transversal_yield_lv([[1, 2, 3], [2, 4], [1]], [], Ans) Sets/[[1, 2, 3], [2, 4], [1]]; Partial_Transversal/[] Sets/[[2, 4], [1]]; Partial_Transversal/[1] Sets/[[1]]; Partial_Transversal/[1, 2] Sets/[[1]]; Partial_Transversal/[1, 4] Sets/[[2, 4], [1]]; Partial_Transversal/[2] Sets/[[1]]; Partial_Transversal/[2, 4] Sets/[]; Partial_Transversal/[2, 4, 1]
""" transversal_yield_lv """ def transversal_yield_lv(sets: List[PyList], so_far: PyList, Answer: Var): print(f'sets/[{", ".join([str(S) for S in sets])}]; so_far_reversed/{reversed(so_far)}') if not sets: yield from unify(reversed(so_far), Answer) else: [S, *Ss] = sets X = Var( ) for _ in member(X, S): for _ in fails(member)(X, so_far): yield from transversal_yield_lv(Ss, PyList([X]) + so_far, Answer) if __name__ == '__main__': print(f'\n{"-"*75}\ntransversal_yield_lv([[1, 2, 3], [2, 4], [1]], [], Ans)\n') Ans = Var( ) for _ in transversal_yield_lv([PyList([1, 2, 3]), PyList([2, 4]), PyList([1])], PyList([]), Ans): print(f'{" "*30} => {Ans}') """ --------------------------------------------------------------------------- transversal_yield_lv([[1, 2, 3], [2, 4], [1]], [], Ans) sets/[[1, 2, 3], [2, 4], [1]]; so_far_reversed/[] sets/[[2, 4], [1]]; so_far_reversed/[1] sets/[[1]]; so_far_reversed/[1, 2] sets/[[1]]; so_far_reversed/[1, 4] sets/[[2, 4], [1]]; so_far_reversed/[2] sets/[[1]]; so_far_reversed/[2, 4] sets/[]; so_far_reversed/[2, 4, 1] => [1, 4, 2]