Ejemplo n.º 1
0
 def additional_answer(self, Houses: SuperSequence):
     (Nat1, Nat2) = n_Vars(2)
     for _ in members([
             House(nationality=Nat1, pet='zebra'),
             House(nationality=Nat2, drink='water')
     ], Houses):
         ans = f'\n\tThe {Nat1} both own a zebra and drink water.' if Nat1 == Nat2 else \
               f'\n\tThe {Nat1} own a zebra, and the {Nat2} drink water.'
         print(ans)
Ejemplo n.º 2
0
def append(Xs: Union[PySequence, Var], Ys: Union[PySequence, Var],
           Zs: Union[PySequence, Var]):
    """
    append([], Ys, Zs).
    append([X|Xs], Ys, [X|Zs]) :- append(Xs, Ys, Zs).

    See discussion in linked_list version.

    This version assumes we are working with Python lists or tuples, i.e., no uninstantiated tails.
  """

    if isinstance(Zs, Var) and (isinstance(Xs, Var) or isinstance(Ys, Var)):
        # Can't have Xs or Ys Var if Zs is Var.
        return

    if isinstance(Zs, Var):
        ListType = type(Xs)
        # Make Zs a list of Var's of length len(Xs) + len(Ys)
        # After this unification, Zs will still be a Var, but
        # by the time we reach this point again, Zs will refer
        # to its trail end, which is not a Var.
        for _ in unify(Zs, ListType(n_Vars(len(Xs) + len(Ys)))):
            yield from append(Xs, Ys, Zs)
        return

    # We now know that: Zs is not a Var -- although it may be a sequence of Vars.
    # Divide up its length among Xs and Ys
    ListType = type(Zs)
    len_Zs = len(Zs)
    for i in range(len_Zs + 1):
        # If Xs or Ys are already instantiated to some fixed length Sequence, unify will fail when given the wrong length.
        for _ in unify_pairs([(Xs, ListType(n_Vars(i))),
                              (Ys, ListType(n_Vars(len_Zs - i)))]):
            # Although the lengths of Xs and Ys vary with i,
            # Xs, Ys, and Zs are all of fixed lengths in which len(Xs) + len(Ys) = len(Zs).
            # Concatenate Xs and Ys and then unify the concatenation with Zs.
            XYs = [
                *Xs.unification_chain_end().args,
                *Ys.unification_chain_end().args
            ]
            yield from unify_sequences(XYs, Zs.args)
Ejemplo n.º 3
0
def append(Xs: Union[LinkedList, Var], Ys: Union[LinkedList, Var],
           Zs: Union[LinkedList, Var]):
    """
    append([], Ys, Zs).
    append([X|Xs], Ys, [X|Zs]) :- append(Xs, Ys, Zs).

  Note that this could just have well have been written:
    append([Z|Xs], Ys, [Z|Zs]) :- append(Xs, Ys, Zs).
  or
    append([W|Xs], Ys, [W|Zs]) :- append(Xs, Ys, Zs).

  We don't have to implicitly favor the Xs.

  No matter what the variable is called, this is really unifying Xs_head and Zs_head.

  append/3 converts between: Xs + Ys <--> Zs

  It does this by moving elements between the Xs and the Zs.
  If we are moving from Zs to Xs + Ys, there will be multiple answers depending on
  how much of Zs is shifted before we let Ys be the rest.

  The function consists of two "clauses" (see prolog definition above), which are tried in sequence.
  
  Clause 1
  This is the step in which we set Xs to [] and set Ys to Zs. No recursive call.
  At this point, earlier recursion calls will have shifted elements between Xs and Zs.
  But those are not visible at this level.

  Clause 2. The recursive step.
  Move an element between Xs and Zs and call append recursively with Xs_Tail and Zs_Tail.
  Since an empty list cannot unify with a LinkedList that has a head and a tail, if either
  Xs or Zs is empty, unify_pairs will fail.

  The actual code is quite short. It's very similar to like the prolog code.
  """

    # Create the existential variables at the start.
    (XZ_Head, Xs_Tail, Zs_Tail) = n_Vars(3)

    for _ in forany([
            # Clause 1.
            lambda: unify_pairs([(Xs, emptyLinkedList), (Ys, Zs)]),
            # Clause 2.
            lambda: forall([
                lambda: unify_pairs([(Xs, LinkedList((XZ_Head, Xs_Tail))),
                                     (Zs, LinkedList((XZ_Head, Zs_Tail)))]),
                lambda: append(Xs_Tail, Ys, Zs_Tail)
            ])
    ]):
        yield
Ejemplo n.º 4
0
 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)
Ejemplo n.º 5
0
 def __getitem__(self, key: Union[int, slice]):
     (prefix, tail) = self.prefix_and_tail()
     stop = key if isinstance(key, int) else \
            key.stop if isinstance(key.stop, int) else \
            len(self) if key.stop is None else \
            None
     if len(prefix) >= stop:
         slice_elements = prefix[key]
         if isinstance(key, int):
             return slice_elements
         else:
             return LinkedList(slice_elements)
     if not isinstance(tail, Var):
         return None
     template = LinkedList(n_Vars(stop))
     for _ in unify(self, template):
         (prefix, _) = template.prefix_and_tail()
         return LinkedList(prefix[key])
Ejemplo n.º 6
0
        yield


if __name__ == '__main__':

    from timeit import default_timer as timer

    (start1, end1, start2, end2) = (timer(), None, None, None)

    Houses = LinkedList([House() for _ in range(5)])
    inp = None
    for _ in zebra_problem(Houses):
        print('\nHouses: ')
        for (indx, house) in enumerate(Houses.to_python_list()):
            print(f'\t{indx+1}. {house}')
        (Nat1, Nat2) = n_Vars(2)
        for _ in members([
                House(nationality=Nat1, pet='zebra'),
                House(nationality=Nat2, drink='water')
        ], Houses):
            ans = f'The {Nat1} both own a zebra and drink water.' if Nat1 == Nat2 else \
                  f'The {Nat1} own a zebra, and the {Nat2} drink water.'
            end1 = timer()
            print(ans)
        inp = input('\nMore? (y, or n)? > ').lower()
        start2 = timer()
        if inp != 'y':
            break

    if inp == 'y':
        print('No more solutions.')
Ejemplo n.º 7
0
  """
    Xs = list(map(PyValue, range(9)))
    Sub_Xs = [PyValue(1), Var(), PyValue(4), Var(), PyValue(8)]
    print(
        f'\nLinkedList(Sub_Xs): {LinkedList(Sub_Xs)}, LinkedList(Xs): {LinkedList(Xs)}'
    )
    for _ in is_a_subsequence_of(Sub_Xs, LinkedList(Xs)):
        print(f'\tLinkedList(Sub_Xs): {LinkedList(Sub_Xs)}')
    Sub_Xs = [PyValue(1), Var(), PyValue(8), Var(), PyValue(7)]
    print(
        f'\nLinkedList(Sub_Xs): {LinkedList(Sub_Xs)}, LinkedList(Xs): {LinkedList(Xs)}'
    )
    for _ in is_a_subsequence_of(Sub_Xs, LinkedList(Xs)):
        print(f'\tLinkedList(Sub_Xs): {LinkedList(Sub_Xs)}')

    (Start, Pivot, End) = n_Vars(3)
    Zs = LinkedList(list(range(10)))

    L = LinkedList(n_Vars(3))
    print(f'\nGiven: L = LinkedList( n_Vars(3) ): {L}')
    E = Var()
    for _ in unify(L, LinkedList([1, 2, 3])):
        print(f'Given: E: {E}, L: {L}')

        print(f'?- LinkedList.member(E, L)')
        for _ in member(E, L):
            print(f'E = {E}')

    A_List = LinkedList([*map(PyValue, [1, 2, 3, 2, 1])])
    E_Sub = [PyValue(2), Var()]
    linkedlistE_Sub = LinkedList(E_Sub)
Ejemplo n.º 8
0
    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()
    Zs = PyTuple(tuple(range(5)))

    print(f'\nappend({Xs}, {Ys}, {Zs})')
    for _ in append(Xs, Ys, Zs):
        print(f'\tXs: {Xs}, Ys: {Ys}, Zs: {Zs}')

    X = tuple(n_Vars(15))
    Y = X[4:8]
    print(f'\nX: {PyTuple(X)}, Y: {PyTuple(Y)}')
    for _ in unify_sequences(Y, tuple(map(PyValue, ['A', 'B', 'C', 'D']))):
        print(
            f"unify_sequences(Y, tuple(map(PyValue, ['A', 'B', 'C', 'D']))) => X: {PyTuple(X)}, Y: {PyTuple(Y)}"
        )

    B = tuple(n_Vars(8))
    print(f'\nB: {PyTuple(B)}')

    for _ in unify(B[3], PyValue('XYZ')):
        print(f"unify(B[3], PyValue('XYZ')) => B: {PyTuple(B)}")