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 // (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(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 =
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 // (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 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 # (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([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 () (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)