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
 20using namespace cvc5;
 21
 22int 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  // (Relation Person)
 43  Sort relationArity1 = solver.mkSetSort(tupleArity1);
 44
 45  // (Tuple Person Person)
 46  Sort tupleArity2 = solver.mkTupleSort({personSort, personSort});
 47  // (Relation 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(Kind::EQUAL, {males, emptySetTerm});
 70  Term isEmpty2 = solver.mkTerm(Kind::EQUAL, {females, emptySetTerm});
 71
 72  // (assert (= people (as set.universe (Relation Person))))
 73  Term peopleAreTheUniverse = solver.mkTerm(Kind::EQUAL, {people, universeSet});
 74  // (assert (not (= males (as set.empty (Relation Person)))))
 75  Term maleSetIsNotEmpty = solver.mkTerm(Kind::NOT, {isEmpty1});
 76  // (assert (not (= females (as set.empty (Relation Person)))))
 77  Term femaleSetIsNotEmpty = solver.mkTerm(Kind::NOT, {isEmpty2});
 78
 79  // (assert (= (set.inter males females)
 80  //            (as set.empty (Relation Person))))
 81  Term malesFemalesIntersection =
 82      solver.mkTerm(Kind::SET_INTER, {males, females});
 83  Term malesAndFemalesAreDisjoint =
 84      solver.mkTerm(Kind::EQUAL, {malesFemalesIntersection, emptySetTerm});
 85
 86  // (assert (not (= father (as set.empty (Relation Person Person)))))
 87  // (assert (not (= mother (as set.empty (Relation Person Person)))))
 88  Term isEmpty3 = solver.mkTerm(Kind::EQUAL, {father, emptyRelationTerm});
 89  Term isEmpty4 = solver.mkTerm(Kind::EQUAL, {mother, emptyRelationTerm});
 90  Term fatherIsNotEmpty = solver.mkTerm(Kind::NOT, {isEmpty3});
 91  Term motherIsNotEmpty = solver.mkTerm(Kind::NOT, {isEmpty4});
 92
 93  // fathers are males
 94  // (assert (set.subset (rel.join father people) males))
 95  Term fathers = solver.mkTerm(Kind::RELATION_JOIN, {father, people});
 96  Term fathersAreMales = solver.mkTerm(Kind::SET_SUBSET, {fathers, males});
 97
 98  // mothers are females
 99  // (assert (set.subset (rel.join mother people) females))
100  Term mothers = solver.mkTerm(Kind::RELATION_JOIN, {mother, people});
101  Term mothersAreFemales = solver.mkTerm(Kind::SET_SUBSET, {mothers, females});
102
103  // (assert (= parent (set.union father mother)))
104  Term unionFatherMother = solver.mkTerm(Kind::SET_UNION, {father, mother});
105  Term parentIsFatherOrMother =
106      solver.mkTerm(Kind::EQUAL, {parent, unionFatherMother});
107
108  // (assert (= ancestor (rel.tclosure parent)))
109  Term transitiveClosure = solver.mkTerm(Kind::RELATION_TCLOSURE, {parent});
110  Term ancestorFormula =
111      solver.mkTerm(Kind::EQUAL, {ancestor, transitiveClosure});
112
113  // (assert (= descendant (rel.transpose descendant)))
114  Term transpose = solver.mkTerm(Kind::RELATION_TRANSPOSE, {ancestor});
115  Term descendantFormula = solver.mkTerm(Kind::EQUAL, {descendant, transpose});
116
117  // (assert (forall ((x Person)) (not (set.member (tuple x x) ancestor))))
118  Term x = solver.mkVar(personSort, "x");
119  Term xxTuple = solver.mkTuple({x, x});
120  Term member = solver.mkTerm(Kind::SET_MEMBER, {xxTuple, ancestor});
121  Term notMember = solver.mkTerm(Kind::NOT, {member});
122
123  Term quantifiedVariables = solver.mkTerm(Kind::VARIABLE_LIST, {x});
124  Term noSelfAncestor =
125      solver.mkTerm(Kind::FORALL, {quantifiedVariables, notMember});
126
127  // formulas
128  solver.assertFormula(peopleAreTheUniverse);
129  solver.assertFormula(maleSetIsNotEmpty);
130  solver.assertFormula(femaleSetIsNotEmpty);
131  solver.assertFormula(malesAndFemalesAreDisjoint);
132  solver.assertFormula(fatherIsNotEmpty);
133  solver.assertFormula(motherIsNotEmpty);
134  solver.assertFormula(fathersAreMales);
135  solver.assertFormula(mothersAreFemales);
136  solver.assertFormula(parentIsFatherOrMother);
137  solver.assertFormula(descendantFormula);
138  solver.assertFormula(ancestorFormula);
139  solver.assertFormula(noSelfAncestor);
140
141  // check sat
142  Result result = solver.checkSat();
143
144  // output
145  std::cout << "Result     = " << result << std::endl;
146  std::cout << "people     = " << solver.getValue(people) << std::endl;
147  std::cout << "males      = " << solver.getValue(males) << std::endl;
148  std::cout << "females    = " << solver.getValue(females) << std::endl;
149  std::cout << "father     = " << solver.getValue(father) << std::endl;
150  std::cout << "mother     = " << solver.getValue(mother) << std::endl;
151  std::cout << "parent     = " << solver.getValue(parent) << std::endl;
152  std::cout << "descendant = " << solver.getValue(descendant) << std::endl;
153  std::cout << "ancestor   = " << solver.getValue(ancestor) << std::endl;
154}
            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
 16import static io.github.cvc5.Kind.*;
 17
 18import io.github.cvc5.*;
 19
 20public class Relations
 21{
 22  public static void main(String[] args) throws CVC5ApiException
 23  {
 24    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      // (Relation Person)
 43      Sort relationArity1 = solver.mkSetSort(tupleArity1);
 44
 45      // (Tuple Person Person)
 46      Sort tupleArity2 = solver.mkTupleSort(new Sort[] {personSort, personSort});
 47      // (Relation 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 (Relation Person))))
 73      Term peopleAreTheUniverse = solver.mkTerm(EQUAL, people, universeSet);
 74      // (assert (not (= males (as set.empty (Relation Person)))))
 75      Term maleSetIsNotEmpty = solver.mkTerm(NOT, isEmpty1);
 76      // (assert (not (= females (as set.empty (Relation Person)))))
 77      Term femaleSetIsNotEmpty = solver.mkTerm(NOT, isEmpty2);
 78
 79      // (assert (= (set.inter males females)
 80      //            (as set.empty (Relation 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 (Relation Person Person)))))
 86      // (assert (not (= mother (as set.empty (Relation 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 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    Context.deletePointers();
152  }
153}
            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
 18import cvc5
 19from cvc5 import Kind
 20
 21if __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    # (Relation Person)
 47    relationArity1 = solver.mkSetSort(tupleArity1)
 48
 49    # (Tuple Person Person)
 50    tupleArity2 = solver.mkTupleSort(personSort, personSort)
 51    # (Relation 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 (Relation Person))))
 77    peopleAreTheUniverse = solver.mkTerm(Kind.EQUAL, people, universeSet)
 78    # (assert (not (= males (as set.empty (Relation Person)))))
 79    maleSetIsNotEmpty = solver.mkTerm(Kind.NOT, isEmpty1)
 80    # (assert (not (= females (as set.empty (Relation Person)))))
 81    femaleSetIsNotEmpty = solver.mkTerm(Kind.NOT, isEmpty2)
 82
 83    # (assert (= (set.inter males females)
 84    #            (as set.empty (Relation 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 (Relation Person Person)))))
 90    # (assert (not (= mother (as set.empty (Relation 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([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 () (Relation Person))
13(declare-fun males () (Relation Person))
14(declare-fun females () (Relation Person))
15(declare-fun father () (Relation Person Person))
16(declare-fun mother () (Relation Person Person))
17(declare-fun parent () (Relation Person Person))
18(declare-fun ancestor () (Relation Person Person))
19(declare-fun descendant () (Relation Person Person))
20
21(assert (= people (as set.universe (Relation Person))))
22(assert (not (= males (as set.empty (Relation Person)))))
23(assert (not (= females (as set.empty (Relation Person)))))
24(assert (= (set.inter males females) (as set.empty (Relation Person))))
25
26; father relation is not empty
27(assert (not (= father (as set.empty (Relation Person Person)))))
28; mother relation is not empty
29(assert (not (= mother (as set.empty (Relation 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)