[2bb500]: examples / family_relations / fc_example.krb  Maximize  Restore  History

Download this file

225 lines (200 with data), 8.3 kB

# $Id$
# 
# Copyright © 2007-2008 Bruce Frederiksen
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.


# Since all other relationships depend on child_parent and sibling
# relationships, we're just going to go ahead and assert all child_parent and
# sibling relationships with forward-chaining rules.  If we use
# backward-chaining rules for these, we would have to re-run the rules each
# time the facts are needed for the same people.  This avoids that.
#
# Establish child_parent relationships:
son_of
    foreach
	family.son_of($child, $father, $mother)
    assert
	family.child_parent($child, $father, father, son)
	family.child_parent($child, $mother, mother, son)

daughter_of
    foreach
	family.daughter_of($child, $father, $mother)
    assert
	family.child_parent($child, $father, father, daughter)
	family.child_parent($child, $mother, mother, daughter)

# Establish sibling relationships:
brothers
    foreach
	family.son_of($brother1, $father, $mother)
	family.son_of($brother2, $father, $mother)
	check $brother1 != $brother2
    assert
	family.siblings($brother1, $brother2, brother, brother)

sisters
    foreach
	family.daughter_of($sister1, $father, $mother)
	family.daughter_of($sister2, $father, $mother)
	check $sister1 != $sister2
    assert
	family.siblings($sister1, $sister2, sister, sister)

brother_and_sister
    foreach
	family.son_of($brother, $father, $mother)
	family.daughter_of($sister, $father, $mother)
    assert
	family.siblings($brother, $sister, sister, brother)
	family.siblings($sister, $brother, brother, sister)

facts_for_bc_rules
    # With no "foreach" clause, this rule will always be triggered just once.
    # These facts could also be universal facts.
    # They translate, for example the first fact means that my parent's
    # "brother" "as an aunt or uncle" (as_au) is my "uncle".
    # The last fact means that my "daughter" "as a niece or nephew" (as_nn)
    # is my sibling's "niece".
    assert
	family.as_au(brother, uncle)
	family.as_au(sister, aunt)
	family.as_nn(son, nephew)
	family.as_nn(daughter, niece)

niece_or_nephew_and_aunt_or_uncle
    foreach
	family.child_parent($nn, $parent, $depth, $_, $child_type)
	family.siblings($parent, $au, $sibling_type, $_)
	family.as_au($sibling_type, $au_type)
	family.as_nn($child_type, $nn_type)
        $greats = ('great',) * len($depth)
    assert
        family.nn_au($nn, $au, $greats, $au_type, $nn_type)

# Note that these family.child_parent have an extra argument to handle
# ('grand',), ('great', 'grand'), etc.
parent_and_child
    foreach
	family.child_parent($child, $parent, $parent_type, $child_type)
    assert
        family.child_parent($child, $parent, (), $parent_type, $child_type)

grand_parent_and_child
    foreach
	family.child_parent($child, $parent, $_, $child_type)
	family.child_parent($parent, $grand_parent, $parent_type, $_)
    assert
        # Note that a comma is not required (but is allowed) for singleton
        # tuples in .krb files; in this case, "(grand)".
        family.child_parent($child, $grand_parent, (grand),
                            $parent_type, $child_type)

great_grand_parent_and_child
    foreach
	family.child_parent($child, $grand_child, $_, $child_type)
        # We use "($a, *$b)" in the next premise so that it won't match ().
	family.child_parent($grand_child, $grand_parent, ($a, *$b),
                            $parent_type, $_)
    assert
        family.child_parent($child, $grand_parent, (great, $a, *$b),
                            $parent_type, $child_type)

first_cousins
    foreach
	family.child_parent($cousin1, $sibling1, $_, $_)
	family.siblings($sibling1, $sibling2, $_, $_)
	family.child_parent($cousin2, $sibling2, $_, $_)
    assert
        family.cousins($cousin1, $cousin2, 1)

nth_cousins
    foreach
	family.child_parent($next_cousin1, $cousin1, $_, $_)
	family.cousins($cousin1, $cousin2, $n)
	family.child_parent($next_cousin2, $cousin2, $_, $_)
	$next_n = $n + 1
    assert
        family.cousins($next_cousin1, $next_cousin2, $next_n)

how_related_child_parent
    foreach
	family.child_parent($person1, $person2, $prefix, $p2_type, $p1_type)
	$relationship = add_prefix($prefix, $p1_type, $p2_type)
    assert
        family.how_related($person1, $person2, $relationship)

how_related_parent_child
    foreach
        # Note that for how_related(Fixed_name, $variable) that this
        # subgoal is run "in reverse":
        #     child_parent($variable, Fixed_name, ...)
        # This is very inefficient the way the following rules were written:
        #         grand_parent_and_child
        #     and great_grand_parent_and_child
        # It is left as an exercise for the reader to determine how to improve
        # these rules.  Here's a way to check whether a pattern variable is
        # bound (only 'variable_name' changes with different variables).  This
        # only checks the top-level binding.  It does not check whether
        # subordinate variables in tuples are bound:
        #     check context.is_bound(contexts.variable('variable_name'))
	family.child_parent($person2, $person1, $prefix, $p1_type, $p2_type)
	$relationship = add_prefix($prefix, $p1_type, $p2_type)
    assert
        family.how_related($person1, $person2, $relationship)

how_related_siblings
    foreach
	family.siblings($person1, $person2, $p2_type, $p1_type)
    assert
        family.how_related($person1, $person2, ($p1_type, $p2_type))

how_related_nn_au
    foreach
	family.nn_au($person1, $person2, $prefix, $p2_type, $p1_type)
	$relationship = add_prefix($prefix, $p1_type, $p2_type)
    assert
        family.how_related($person1, $person2, $relationship)

how_related_au_nn
    foreach
        # Here is another case where how_related(Fixed_name, $variable) is
        # very inefficient because of the way the
        # great_niece_or_nephew_and_aunt_or_uncle rule is written.
	family.nn_au($person2, $person1, $prefix, $p1_type, $p2_type)
	$relationship = add_prefix($prefix, $p1_type, $p2_type)
    assert
        family.how_related($person1, $person2, $relationship)

how_related_cousins
    foreach
	family.cousins($cousin1, $cousin2, $n)
        $nth = nth($n)
    assert
        family.how_related($cousin1, $cousin2, ($nth, cousins))

how_related_removed_cousins
    foreach
        family.child_parent($removed_cousin1, $cousin1, $grand, $_, $_)
	family.cousins($cousin1, $cousin2, $n)
        $nth = nth($n)
        $r1 = len($grand) + 1
    assert
        family.how_related($removed_cousin1, $cousin2,
                           ($nth, cousins, $r1, removed))

how_related_cousins_removed
    foreach
	family.cousins($cousin1, $cousin2, $n)
        family.child_parent($removed_cousin2, $cousin2, $grand, $_, $_)
        $nth = nth($n)
        $r1 = len($grand) + 1
    assert
        family.how_related($cousin1, $removed_cousin2,
                           ($nth, cousins, $r1, removed))


fc_extras
    def nth(n):
        if n % 10 not in (1, 2, 3) or 10 < n % 100 < 20: return "%dth" % n
        if n % 10 == 1: return "%dst" % n
        if n % 10 == 2: return "%dnd" % n
        if n % 10 == 3: return "%drd" % n

    def add_prefix(prefix, x, y):
        if not prefix: return (x, y)
	return (prefix + (x,), prefix + (y,))