Theory of Relations 
This simple example demonstrates the combined theory of finite sets and finite relations using a family tree. Relations are defined as sets of tuples with arity \(\geq 1\) . The example includes the unary relations \(people, males,\) and \(females\) and the binary relations \(father, mother, parent, ancestor\) , and \(descendant\) .
We have the following list of constraints:
- 
           
All relations are nonempty.
 - 
           
People is the universe set.
 - 
           
Males and females are disjoint sets (i.e., \(males \cap females = \phi\) ).
 - 
           
Fathers are males (i.e., \(father \bowtie people \subseteq males\) ) * .
 - 
           
Mothers are females (i.e., \(mother \bowtie people \subseteq females\) ).
 - 
           
A parent is a father or a mother (i.e., \(parent = father \cup mother\) ).
 - 
           
Ancestor relation is the transitive closure of parent (i.e., \(ancestor = parent^{+}\) ).
 - 
           
Descendant relation is the transpose of ancestor (i.e., \(descendant = ancestor^{-1}\) ).
 - 
           
No self ancestor (i.e., \(\forall x: Person. \langle x, x \rangle \not\in ancestor\) ).
 
examples/api/cpp/relations.cpp
  1 /******************************************************************************
  2  * Top contributors (to current version):
  3  *   Mudathir Mohamed, Mathias Preiner
  4  *
  5  * This file is part of the cvc5 project.
  6  *
  7  * Copyright (c) 2009-2022 by the authors listed in the file AUTHORS
  8  * in the top-level source directory and their institutional affiliations.
  9  * All rights reserved.  See the file COPYING in the top-level source
 10  * directory for licensing information.
 11  * ****************************************************************************
 12  *
 13  * A simple demonstration of reasoning about relations with cvc5 via C++ API.
 14  */
 15 
 16 #include <cvc5/cvc5.h>
 17 
 18 #include <iostream>
 19 
 20 using namespace cvc5;
 21 
 22 int main()
 23 {
 24   Solver solver;
 25 
 26   // Set the logic
 27   solver.setLogic("ALL");
 28 
 29   // options
 30   solver.setOption("produce-models", "true");
 31   // we need finite model finding to answer sat problems with universal
 32   // quantified formulas
 33   solver.setOption("finite-model-find", "true");
 34   // we need sets extension to support set.universe operator
 35   solver.setOption("sets-ext", "true");
 36 
 37   // (declare-sort Person 0)
 38   Sort personSort = solver.mkUninterpretedSort("Person");
 39 
 40   // (Tuple Person)
 41   Sort tupleArity1 = solver.mkTupleSort({personSort});
 42   // (Set (Tuple Person))
 43   Sort relationArity1 = solver.mkSetSort(tupleArity1);
 44 
 45   // (Tuple Person Person)
 46   Sort tupleArity2 = solver.mkTupleSort({personSort, personSort});
 47   // (Set (Tuple Person Person))
 48   Sort relationArity2 = solver.mkSetSort(tupleArity2);
 49 
 50   // empty set
 51   Term emptySetTerm = solver.mkEmptySet(relationArity1);
 52 
 53   // empty relation
 54   Term emptyRelationTerm = solver.mkEmptySet(relationArity2);
 55 
 56   // universe set
 57   Term universeSet = solver.mkUniverseSet(relationArity1);
 58 
 59   // variables
 60   Term people = solver.mkConst(relationArity1, "people");
 61   Term males = solver.mkConst(relationArity1, "males");
 62   Term females = solver.mkConst(relationArity1, "females");
 63   Term father = solver.mkConst(relationArity2, "father");
 64   Term mother = solver.mkConst(relationArity2, "mother");
 65   Term parent = solver.mkConst(relationArity2, "parent");
 66   Term ancestor = solver.mkConst(relationArity2, "ancestor");
 67   Term descendant = solver.mkConst(relationArity2, "descendant");
 68 
 69   Term isEmpty1 = solver.mkTerm(EQUAL, {males, emptySetTerm});
 70   Term isEmpty2 = solver.mkTerm(EQUAL, {females, emptySetTerm});
 71 
 72   // (assert (= people (as set.universe (Set (Tuple Person)))))
 73   Term peopleAreTheUniverse = solver.mkTerm(EQUAL, {people, universeSet});
 74   // (assert (not (= males (as set.empty (Set (Tuple Person))))))
 75   Term maleSetIsNotEmpty = solver.mkTerm(NOT, {isEmpty1});
 76   // (assert (not (= females (as set.empty (Set (Tuple Person))))))
 77   Term femaleSetIsNotEmpty = solver.mkTerm(NOT, {isEmpty2});
 78 
 79   // (assert (= (set.inter males females)
 80   //            (as set.empty (Set (Tuple Person)))))
 81   Term malesFemalesIntersection = solver.mkTerm(SET_INTER, {males, females});
 82   Term malesAndFemalesAreDisjoint =
 83       solver.mkTerm(EQUAL, {malesFemalesIntersection, emptySetTerm});
 84 
 85   // (assert (not (= father (as set.empty (Set (Tuple Person Person))))))
 86   // (assert (not (= mother (as set.empty (Set (Tuple Person Person))))))
 87   Term isEmpty3 = solver.mkTerm(EQUAL, {father, emptyRelationTerm});
 88   Term isEmpty4 = solver.mkTerm(EQUAL, {mother, emptyRelationTerm});
 89   Term fatherIsNotEmpty = solver.mkTerm(NOT, {isEmpty3});
 90   Term motherIsNotEmpty = solver.mkTerm(NOT, {isEmpty4});
 91 
 92   // fathers are males
 93   // (assert (set.subset (rel.join father people) males))
 94   Term fathers = solver.mkTerm(RELATION_JOIN, {father, people});
 95   Term fathersAreMales = solver.mkTerm(SET_SUBSET, {fathers, males});
 96 
 97   // mothers are females
 98   // (assert (set.subset (rel.join mother people) females))
 99   Term mothers = solver.mkTerm(RELATION_JOIN, {mother, people});
100   Term mothersAreFemales = solver.mkTerm(SET_SUBSET, {mothers, females});
101 
102   // (assert (= parent (set.union father mother)))
103   Term unionFatherMother = solver.mkTerm(SET_UNION, {father, mother});
104   Term parentIsFatherOrMother =
105       solver.mkTerm(EQUAL, {parent, unionFatherMother});
106 
107   // (assert (= ancestor (rel.tclosure parent)))
108   Term transitiveClosure = solver.mkTerm(RELATION_TCLOSURE, {parent});
109   Term ancestorFormula = solver.mkTerm(EQUAL, {ancestor, transitiveClosure});
110 
111   // (assert (= descendant (rel.transpose descendant)))
112   Term transpose = solver.mkTerm(RELATION_TRANSPOSE, {ancestor});
113   Term descendantFormula = solver.mkTerm(EQUAL, {descendant, transpose});
114 
115   // (assert (forall ((x Person)) (not (set.member (tuple x x) ancestor))))
116   Term x = solver.mkVar(personSort, "x");
117   Term xxTuple = solver.mkTuple({personSort, personSort}, {x, x});
118   Term member = solver.mkTerm(SET_MEMBER, {xxTuple, ancestor});
119   Term notMember = solver.mkTerm(NOT, {member});
120 
121   Term quantifiedVariables = solver.mkTerm(VARIABLE_LIST, {x});
122   Term noSelfAncestor = solver.mkTerm(FORALL, {quantifiedVariables, notMember});
123 
124   // formulas
125   solver.assertFormula(peopleAreTheUniverse);
126   solver.assertFormula(maleSetIsNotEmpty);
127   solver.assertFormula(femaleSetIsNotEmpty);
128   solver.assertFormula(malesAndFemalesAreDisjoint);
129   solver.assertFormula(fatherIsNotEmpty);
130   solver.assertFormula(motherIsNotEmpty);
131   solver.assertFormula(fathersAreMales);
132   solver.assertFormula(mothersAreFemales);
133   solver.assertFormula(parentIsFatherOrMother);
134   solver.assertFormula(descendantFormula);
135   solver.assertFormula(ancestorFormula);
136   solver.assertFormula(noSelfAncestor);
137 
138   // check sat
139   Result result = solver.checkSat();
140 
141   // output
142   std::cout << "Result     = " << result << std::endl;
143   std::cout << "people     = " << solver.getValue(people) << std::endl;
144   std::cout << "males      = " << solver.getValue(males) << std::endl;
145   std::cout << "females    = " << solver.getValue(females) << std::endl;
146   std::cout << "father     = " << solver.getValue(father) << std::endl;
147   std::cout << "mother     = " << solver.getValue(mother) << std::endl;
148   std::cout << "parent     = " << solver.getValue(parent) << std::endl;
149   std::cout << "descendant = " << solver.getValue(descendant) << std::endl;
150   std::cout << "ancestor   = " << solver.getValue(ancestor) << std::endl;
151 }
            examples/api/java/Relations.java
  1 /******************************************************************************
  2  * Top contributors (to current version):
  3  *   Mudathir Mohamed, Andres Noetzli, Aina Niemetz
  4  *
  5  * This file is part of the cvc5 project.
  6  *
  7  * Copyright (c) 2009-2022 by the authors listed in the file AUTHORS
  8  * in the top-level source directory and their institutional affiliations.
  9  * All rights reserved.  See the file COPYING in the top-level source
 10  * directory for licensing information.
 11  * ****************************************************************************
 12  *
 13  * A simple demonstration of reasoning about relations with cvc5 via Java API.
 14  */
 15 
 16 import static io.github.cvc5.Kind.*;
 17 
 18 import io.github.cvc5.*;
 19 
 20 public class Relations
 21 {
 22   public static void main(String[] args) throws CVC5ApiException
 23   {
 24     try (Solver solver = new Solver())
 25     {
 26       // Set the logic
 27       solver.setLogic("ALL");
 28 
 29       // options
 30       solver.setOption("produce-models", "true");
 31       // we need finite model finding to answer sat problems with universal
 32       // quantified formulas
 33       solver.setOption("finite-model-find", "true");
 34       // we need sets extension to support set.universe operator
 35       solver.setOption("sets-ext", "true");
 36 
 37       // (declare-sort Person 0)
 38       Sort personSort = solver.mkUninterpretedSort("Person");
 39 
 40       // (Tuple Person)
 41       Sort tupleArity1 = solver.mkTupleSort(new Sort[] {personSort});
 42       // (Set (Tuple Person))
 43       Sort relationArity1 = solver.mkSetSort(tupleArity1);
 44 
 45       // (Tuple Person Person)
 46       Sort tupleArity2 = solver.mkTupleSort(new Sort[] {personSort, personSort});
 47       // (Set (Tuple Person Person))
 48       Sort relationArity2 = solver.mkSetSort(tupleArity2);
 49 
 50       // empty set
 51       Term emptySetTerm = solver.mkEmptySet(relationArity1);
 52 
 53       // empty relation
 54       Term emptyRelationTerm = solver.mkEmptySet(relationArity2);
 55 
 56       // universe set
 57       Term universeSet = solver.mkUniverseSet(relationArity1);
 58 
 59       // variables
 60       Term people = solver.mkConst(relationArity1, "people");
 61       Term males = solver.mkConst(relationArity1, "males");
 62       Term females = solver.mkConst(relationArity1, "females");
 63       Term father = solver.mkConst(relationArity2, "father");
 64       Term mother = solver.mkConst(relationArity2, "mother");
 65       Term parent = solver.mkConst(relationArity2, "parent");
 66       Term ancestor = solver.mkConst(relationArity2, "ancestor");
 67       Term descendant = solver.mkConst(relationArity2, "descendant");
 68 
 69       Term isEmpty1 = solver.mkTerm(EQUAL, males, emptySetTerm);
 70       Term isEmpty2 = solver.mkTerm(EQUAL, females, emptySetTerm);
 71 
 72       // (assert (= people (as set.universe (Set (Tuple Person)))))
 73       Term peopleAreTheUniverse = solver.mkTerm(EQUAL, people, universeSet);
 74       // (assert (not (= males (as set.empty (Set (Tuple Person))))))
 75       Term maleSetIsNotEmpty = solver.mkTerm(NOT, isEmpty1);
 76       // (assert (not (= females (as set.empty (Set (Tuple Person))))))
 77       Term femaleSetIsNotEmpty = solver.mkTerm(NOT, isEmpty2);
 78 
 79       // (assert (= (set.inter males females)
 80       //            (as set.empty (Set (Tuple Person)))))
 81       Term malesFemalesIntersection = solver.mkTerm(SET_INTER, males, females);
 82       Term malesAndFemalesAreDisjoint =
 83           solver.mkTerm(EQUAL, malesFemalesIntersection, emptySetTerm);
 84 
 85       // (assert (not (= father (as set.empty (Set (Tuple Person Person))))))
 86       // (assert (not (= mother (as set.empty (Set (Tuple Person Person))))))
 87       Term isEmpty3 = solver.mkTerm(EQUAL, father, emptyRelationTerm);
 88       Term isEmpty4 = solver.mkTerm(EQUAL, mother, emptyRelationTerm);
 89       Term fatherIsNotEmpty = solver.mkTerm(NOT, isEmpty3);
 90       Term motherIsNotEmpty = solver.mkTerm(NOT, isEmpty4);
 91 
 92       // fathers are males
 93       // (assert (set.subset (rel.join father people) males))
 94       Term fathers = solver.mkTerm(RELATION_JOIN, father, people);
 95       Term fathersAreMales = solver.mkTerm(SET_SUBSET, fathers, males);
 96 
 97       // mothers are females
 98       // (assert (set.subset (rel.join mother people) females))
 99       Term mothers = solver.mkTerm(RELATION_JOIN, mother, people);
100       Term mothersAreFemales = solver.mkTerm(SET_SUBSET, mothers, females);
101 
102       // (assert (= parent (set.union father mother)))
103       Term unionFatherMother = solver.mkTerm(SET_UNION, father, mother);
104       Term parentIsFatherOrMother = solver.mkTerm(EQUAL, parent, unionFatherMother);
105 
106       // (assert (= ancestor (rel.tclosure parent)))
107       Term transitiveClosure = solver.mkTerm(RELATION_TCLOSURE, parent);
108       Term ancestorFormula = solver.mkTerm(EQUAL, ancestor, transitiveClosure);
109 
110       // (assert (= descendant (rel.transpose ancestor)))
111       Term transpose = solver.mkTerm(RELATION_TRANSPOSE, ancestor);
112       Term descendantFormula = solver.mkTerm(EQUAL, descendant, transpose);
113 
114       // (assert (forall ((x Person)) (not (set.member (tuple x x) ancestor))))
115       Term x = solver.mkVar(personSort, "x");
116       Term xxTuple = solver.mkTuple(new Sort[] {personSort, personSort}, new Term[] {x, x});
117       Term member = solver.mkTerm(SET_MEMBER, xxTuple, ancestor);
118       Term notMember = solver.mkTerm(NOT, member);
119 
120       Term quantifiedVariables = solver.mkTerm(VARIABLE_LIST, x);
121       Term noSelfAncestor = solver.mkTerm(FORALL, quantifiedVariables, notMember);
122 
123       // formulas
124       solver.assertFormula(peopleAreTheUniverse);
125       solver.assertFormula(maleSetIsNotEmpty);
126       solver.assertFormula(femaleSetIsNotEmpty);
127       solver.assertFormula(malesAndFemalesAreDisjoint);
128       solver.assertFormula(fatherIsNotEmpty);
129       solver.assertFormula(motherIsNotEmpty);
130       solver.assertFormula(fathersAreMales);
131       solver.assertFormula(mothersAreFemales);
132       solver.assertFormula(parentIsFatherOrMother);
133       solver.assertFormula(descendantFormula);
134       solver.assertFormula(ancestorFormula);
135       solver.assertFormula(noSelfAncestor);
136 
137       // check sat
138       Result result = solver.checkSat();
139 
140       // output
141       System.out.println("Result     = " + result);
142       System.out.println("people     = " + solver.getValue(people));
143       System.out.println("males      = " + solver.getValue(males));
144       System.out.println("females    = " + solver.getValue(females));
145       System.out.println("father     = " + solver.getValue(father));
146       System.out.println("mother     = " + solver.getValue(mother));
147       System.out.println("parent     = " + solver.getValue(parent));
148       System.out.println("descendant = " + solver.getValue(descendant));
149       System.out.println("ancestor   = " + solver.getValue(ancestor));
150     }
151   }
152 }
            examples/api/python/relations.py
  1 #!/usr/bin/env python
  2 ###############################################################################
  3 # Top contributors (to current version):
  4 #   Mudathir Mohamed, Aina Niemetz, Alex Ozdemir
  5 #
  6 # This file is part of the cvc5 project.
  7 #
  8 # Copyright (c) 2009-2022 by the authors listed in the file AUTHORS
  9 # in the top-level source directory and their institutional affiliations.
 10 # All rights reserved.  See the file COPYING in the top-level source
 11 # directory for licensing information.
 12 # #############################################################################
 13 #
 14 # A simple demonstration of the solving capabilities of the cvc5 relations solver
 15 # through the Python API. This is a direct translation of relations.cpp.
 16 ##
 17 
 18 import cvc5
 19 from cvc5 import Kind
 20 
 21 if __name__ == "__main__":
 22     solver = cvc5.Solver()
 23 
 24     # Set the logic
 25     solver.setLogic("ALL")
 26 
 27     # options
 28     solver.setOption("produce-models", "true")
 29     # we need finite model finding to answer sat problems with universal
 30     # quantified formulas
 31     solver.setOption("finite-model-find", "true")
 32     # we need sets extension to support set.universe operator
 33     solver.setOption("sets-ext", "true")
 34 
 35     integer = solver.getIntegerSort()
 36     set_ = solver.mkSetSort(integer)
 37 
 38     # Verify union distributions over intersection
 39     # (A union B) intersection C = (A intersection C) union (B intersection C)
 40 
 41     # (declare-sort Person 0)
 42     personSort = solver.mkUninterpretedSort("Person")
 43 
 44     # (Tuple Person)
 45     tupleArity1 = solver.mkTupleSort(personSort)
 46     # (Set (Tuple Person))
 47     relationArity1 = solver.mkSetSort(tupleArity1)
 48 
 49     # (Tuple Person Person)
 50     tupleArity2 = solver.mkTupleSort(personSort, personSort)
 51     # (Set (Tuple Person Person))
 52     relationArity2 = solver.mkSetSort(tupleArity2)
 53 
 54     # empty set
 55     emptySetTerm = solver.mkEmptySet(relationArity1)
 56 
 57     # empty relation
 58     emptyRelationTerm = solver.mkEmptySet(relationArity2)
 59 
 60     # universe set
 61     universeSet = solver.mkUniverseSet(relationArity1)
 62 
 63     # variables
 64     people = solver.mkConst(relationArity1, "people")
 65     males = solver.mkConst(relationArity1, "males")
 66     females = solver.mkConst(relationArity1, "females")
 67     father = solver.mkConst(relationArity2, "father")
 68     mother = solver.mkConst(relationArity2, "mother")
 69     parent = solver.mkConst(relationArity2, "parent")
 70     ancestor = solver.mkConst(relationArity2, "ancestor")
 71     descendant = solver.mkConst(relationArity2, "descendant")
 72 
 73     isEmpty1 = solver.mkTerm(Kind.EQUAL, males, emptySetTerm)
 74     isEmpty2 = solver.mkTerm(Kind.EQUAL, females, emptySetTerm)
 75 
 76     # (assert (= people (as set.universe (Set (Tuple Person)))))
 77     peopleAreTheUniverse = solver.mkTerm(Kind.EQUAL, people, universeSet)
 78     # (assert (not (= males (as set.empty (Set (Tuple Person))))))
 79     maleSetIsNotEmpty = solver.mkTerm(Kind.NOT, isEmpty1)
 80     # (assert (not (= females (as set.empty (Set (Tuple Person))))))
 81     femaleSetIsNotEmpty = solver.mkTerm(Kind.NOT, isEmpty2)
 82 
 83     # (assert (= (set.inter males females)
 84     #            (as set.empty (Set (Tuple Person)))))
 85     malesFemalesIntersection = solver.mkTerm(Kind.SET_INTER, males, females)
 86     malesAndFemalesAreDisjoint = \
 87             solver.mkTerm(Kind.EQUAL, malesFemalesIntersection, emptySetTerm)
 88 
 89     # (assert (not (= father (as set.empty (Set (Tuple Person Person))))))
 90     # (assert (not (= mother (as set.empty (Set (Tuple Person Person))))))
 91     isEmpty3 = solver.mkTerm(Kind.EQUAL, father, emptyRelationTerm)
 92     isEmpty4 = solver.mkTerm(Kind.EQUAL, mother, emptyRelationTerm)
 93     fatherIsNotEmpty = solver.mkTerm(Kind.NOT, isEmpty3)
 94     motherIsNotEmpty = solver.mkTerm(Kind.NOT, isEmpty4)
 95 
 96     # fathers are males
 97     # (assert (set.subset (rel.join father people) males))
 98     fathers = solver.mkTerm(Kind.RELATION_JOIN, father, people)
 99     fathersAreMales = solver.mkTerm(Kind.SET_SUBSET, fathers, males)
100 
101     # mothers are females
102     # (assert (set.subset (rel.join mother people) females))
103     mothers = solver.mkTerm(Kind.RELATION_JOIN, mother, people)
104     mothersAreFemales = solver.mkTerm(Kind.SET_SUBSET, mothers, females)
105 
106     # (assert (= parent (set.union father mother)))
107     unionFatherMother = solver.mkTerm(Kind.SET_UNION, father, mother)
108     parentIsFatherOrMother = \
109             solver.mkTerm(Kind.EQUAL, parent, unionFatherMother)
110 
111     # (assert (= ancestor (rel.tclosure parent)))
112     transitiveClosure = solver.mkTerm(Kind.RELATION_TCLOSURE, parent)
113     ancestorFormula = solver.mkTerm(Kind.EQUAL, ancestor, transitiveClosure)
114 
115     # (assert (= descendant (rel.transpose ancestor)))
116     transpose = solver.mkTerm(Kind.RELATION_TRANSPOSE, ancestor)
117     descendantFormula = solver.mkTerm(Kind.EQUAL, descendant, transpose)
118 
119     # (assert (forall ((x Person)) (not (set.member (tuple x x) ancestor))))
120     x = solver.mkVar(personSort, "x")
121     xxTuple = solver.mkTuple([personSort, personSort], [x, x])
122     member = solver.mkTerm(Kind.SET_MEMBER, xxTuple, ancestor)
123     notMember = solver.mkTerm(Kind.NOT, member)
124 
125     quantifiedVariables = solver.mkTerm(Kind.VARIABLE_LIST, x)
126     noSelfAncestor = solver.mkTerm(Kind.FORALL, quantifiedVariables, notMember)
127 
128     # formulas
129     solver.assertFormula(peopleAreTheUniverse)
130     solver.assertFormula(maleSetIsNotEmpty)
131     solver.assertFormula(femaleSetIsNotEmpty)
132     solver.assertFormula(malesAndFemalesAreDisjoint)
133     solver.assertFormula(fatherIsNotEmpty)
134     solver.assertFormula(motherIsNotEmpty)
135     solver.assertFormula(fathersAreMales)
136     solver.assertFormula(mothersAreFemales)
137     solver.assertFormula(parentIsFatherOrMother)
138     solver.assertFormula(descendantFormula)
139     solver.assertFormula(ancestorFormula)
140     solver.assertFormula(noSelfAncestor)
141 
142     # check sat
143     result = solver.checkSat()
144 
145     # output
146     print("Result     = {}".format(result))
147     print("people     = {}".format(solver.getValue(people)))
148     print("males      = {}".format(solver.getValue(males)))
149     print("females    = {}".format(solver.getValue(females)))
150     print("father     = {}".format(solver.getValue(father)))
151     print("mother     = {}".format(solver.getValue(mother)))
152     print("parent     = {}".format(solver.getValue(parent)))
153     print("descendant = {}".format(solver.getValue(descendant)))
154     print("ancestor   = {}".format(solver.getValue(ancestor)))
            examples/api/smtlib/relations.smt2
 1 (set-logic ALL)
 2 
 3 (set-option :produce-models true)
 4 ; we need finite model finding to answer sat problems with universal
 5 ; quantified formulas
 6 (set-option :finite-model-find true)
 7 ; we need sets extension to support set.universe operator
 8 (set-option :sets-ext true)
 9 
10 (declare-sort Person 0)
11 
12 (declare-fun people () (Set (Tuple Person)))
13 (declare-fun males () (Set (Tuple Person)))
14 (declare-fun females () (Set (Tuple Person)))
15 (declare-fun father () (Set (Tuple Person Person)))
16 (declare-fun mother () (Set (Tuple Person Person)))
17 (declare-fun parent () (Set (Tuple Person Person)))
18 (declare-fun ancestor () (Set (Tuple Person Person)))
19 (declare-fun descendant () (Set (Tuple Person Person)))
20 
21 (assert (= people (as set.universe (Set (Tuple Person)))))
22 (assert (not (= males (as set.empty (Set (Tuple Person))))))
23 (assert (not (= females (as set.empty (Set (Tuple Person))))))
24 (assert (= (set.inter males females) (as set.empty (Set (Tuple Person)))))
25 
26 ; father relation is not empty
27 (assert (not (= father (as set.empty (Set (Tuple Person Person))))))
28 ; mother relation is not empty
29 (assert (not (= mother (as set.empty (Set (Tuple Person Person))))))
30 ; fathers are males
31 (assert (set.subset (rel.join father people) males))
32 ; mothers are females
33 (assert (set.subset (rel.join mother people) females))
34 ; parent
35 (assert (= parent (set.union father mother)))
36 ; no self ancestor
37 (assert (forall ((x Person)) (not (set.member (tuple x x) ancestor))))
38 ; ancestor
39 (assert (= ancestor (rel.tclosure parent)))
40 ; ancestor
41 (assert (= descendant (rel.transpose ancestor)))
42 
43 (check-sat)
44 (get-model)