def test_two_without_branching(self): with conj(traveller), conj as testConj: Eq(traveller, self.var1) Eq(traveller, 'Alice') result = list(testConj.run()) self.assertEqual(len(result), 1) self.assertEqual(result[0][self.var1], 'Alice')
def rule1(street): """1. There are five houses.""" with conj(house0, house1, house2, house3, house4): isHouse(house0) isHouse(house1) isHouse(house2) isHouse(house3) isHouse(house4) Eq(street, [house0, house1, house2, house3, house4])
def indexoIs(index, val, lst): with conj as base: firsto(lst, val) with conj(rest), conj as recurse: resto(lst, rest) indexoIs(index - 1, val, rest) if index <= 0: return base else: return recurse
def test_two_with_branching(self): with conj(rattle, dum), conj as testConj: with disj: Eq(rattle, 'spoiled') Eq(rattle, 'spoilt') Eq(rattle, self.var2) Eq(dum, 'angry') Eq(dum, self.var1) result = list(testConj.run()) self.assertEqual(len(result), 2) for r in result: self.assertEqual(r[self.var1], 'angry') isSpoiled = [st for st in result if st[self.var2] == 'spoiled'] isSpoilt = [st for st in result if st[self.var2] == 'spoilt'] self.assertEqual(len(isSpoiled), 1) self.assertEqual(len(isSpoilt), 1)
def __run__(self, state): lst = state.reify(self.lst) start = state.reify(self.start) end = state.reify(self.end) sublst = state.reify(self.sublst) lvar_count = varq(lst) + varq(start) + varq(end) + varq(sublst) if lvar_count > 1: with conj(lst_len), conj as full_gen: list_leno(lst, lst_len) rangeo(start) rangeo(end) sliceo(lst, start, end, sublst) yield from full_gen.run(state) elif varq(lst): if start is None: if end is None: # If both start and end are none, # then the lst and sublst are the # same. yield from Eq(lst, sublst).run(state) return elif end >= 0: # The end is a positive number, the start is # undefined, therefore the list could be the # sublist or go past the end. if end < len(sublst): yield state.update(valid=False) return else: lst_len = end else: # If we know how far from the end it is, # then we know the total length of the # list because everything before the # end is the sublst. with conj as bounded_length: list_leno(lst, len(sublst) + -end) sliceo(lst, start, end, sublst) yield from bounded_length.run(state) return elif start >= 0: if end is None: # Full length is known because start is where # it begins, and its end matches the end of the # sublst. lst_len = start + len(sublst) with conj as bounded_length: list_leno(lst, len(sublst) + start) sliceo(lst, start, end, sublst) yield from bounded_length.run(state) return elif end >= 0: # Where end is the last value from the lst in the # sublst, we know that the lst is at least that long, # but could be longer. if (end - start) < len(sublst): yield state.update(valid=False) return else: lst_len = min(end - start, len(sublst)) else: # Since we know where it starts, the interval in the middle, and # how far from the end the end of the sublst is, that means # that lst can only have one length. with conj as bounded_length: list_leno(lst, start + len(sublst) - end) sliceo(lst, start, end, sublst) yield from bounded_length.run(state) return else: if end is None: # The end will match the list, the position of the front # of the sublst is defined from the end, therefore the # start can't go before the front of the sublst, and # the lst can be any length that's longer than the sublst. if -start < len(sublst): yield state.update(valid=False) return else: lst_len = max(len(sublst), -start) elif end >= 0: # The start is measured from the back, the end from the beginning. # Where either the start could hang off the beginning or the end # could hang off the end of `lst` and still match the sublist, # ex. ['Mad Hatter', 'March Hare', 'The Dormouse'][-1:100] == ['The Dormouse'] # and ['March Hare', 'The Dormouse'][-1:100] == ['The Dormouse'] # Multiple lists can match, limited by the absolute value of the largest # absolute value between the start and end, so in the above example the # list could be as long as 100 elements and still return the same value # so long as the last value is 'The Dormouse'. if end < len(sublst) or abs(start) < len(sublst): yield state.update(valid=False) return else: lst_len = len(sublst) while lst_len <= (max(end, abs(start) + 1)): with conj as lst_gen: list_leno(lst, lst_len) sliceo(lst, start, end, sublst) yield from lst_gen.run(state) lst_len += 1 return else: if end <= start: yield from Eq(lst, []).run(state) return lst_len = -start while True: with conj as lst_gen: list_leno(lst, lst_len) sliceo(lst, start, end, sublst) yield from lst_gen.run(state) lst_len += 1 elif varq(sublst): yield from Eq(sublst, lst[start:end]).run(state) elif varq(start): front = lst[:end] if len(sublst) > len(front): yield state.update(valid=False) else: start_val_pos = end - len(sublst) start_val_neg = start_val_pos - len(lst) if start_val_pos > 0: with conj as get_start: with disj: Eq(start, start_val_pos) Eq(start, start_val_neg) sliceo(lst, start, end, sublst) yield from get_start.run(state) else: with conj as get_start_zero: with disj: Eq(start, None) Eq(start, 0) sliceo(lst, start, end, sublst) yield from get_start_zero.run(state) start_val = -1 while True: with conj as get_start: with disj: Eq(start, start_val) sliceo(lst, start, end, sublst) yield from get_start.run(state) start_val -= 1 elif varq(end): back = lst[start:] if len(sublst) > len(back): yield state.update(valid=False) else: end_val_pos = len(sublst) + start if end_val_pos < len(lst): end_val_neg = end_val_pos - len(lst) with conj as get_end: with disj: Eq(end, end_val_pos) Eq(end, end_val_neg) sliceo(lst, start, end, sublst) yield from get_end.run(state) else: with conj as get_endless: Eq(end, None) sliceo(lst, start, end, sublst) yield from get_endless.run(state) while True: with conj as get_end: Eq(end, end_val_pos) sliceo(lst, start, end, sublst) yield from get_end.run(state) end_val_pos += 1 else: if len(sublst) > len(lst): yield state.update(valid=False) else: yield from Eq(lst[start:end], sublst).run(state)
def isHouse(var): with conj(nationality, pet, color, drink, brand): Eq(var, [nationality, pet, color, drink, brand])
def rule10(street): """10. The Norwegian lives in the first house.""" with conj(house): firsto(street, house) indexoIs(nati, norwegian, house)
def rule9(street): """9. In the middle house they drink milk.""" with conj(house): indexoIs(2, house, street) indexoIs(drinki, milk, house)
def rule5(street): """5. The green house is immediately to the left of the white house.""" with conj(left, right): inordero(left, right, street) indexoIs(colori, green, left) indexoIs(colori, white, right)
def rule0(street): """Who Owns the Zebra?""" with conj(house): membero(house, street) indexoIs(peti, "zebra", house)