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)