Connect++ 0.4.0
A fast, readable connection prover for first-order logic.
Loading...
Searching...
No Matches
Unifier Class Reference

Wrap up various applications of unificiation into a single class: all the unification you need to do happens here. More...

#include <Unifier.hpp>

Collaboration diagram for Unifier:

Public Member Functions

 Unifier ()
 There isn't really much to initialize.
 
 Unifier (const Unifier &)=delete
 You really only need one Unifier!
 
 Unifier (const Unifier &&)=delete
 
Unifieroperator= (const Unifier &)=delete
 
Unifieroperator= (const Unifier &&)=delete
 
Substitution get_substitution () const
 Trivial get methods for the result.
 
UnificationOutcome operator() (Term *, Term *)
 Implementation of unification for a pair of Terms.
 
UnificationOutcome operator() (const vector< Term * > &, const vector< Term * > &)
 The same as the main operator(), but you've already extracted the arguments for the things of interest into lists.
 
UnificationOutcome operator() (Literal *, Literal *)
 Unification of Literals.
 
UnificationOutcome operator() (const Literal &, const Literal &)
 
void backtrack ()
 Apply the backtracking process to the substitution that has been constructed.
 
string to_string (bool subbed=false) const
 Make a nice string representation.
 

Private Member Functions

UnificationOutcome complete_unification ()
 Implementation of unification: all the real work happens here.
 

Private Attributes

Substitution s
 Build the resulting substitution here.
 
deque< UPair > to_do
 Queue used by complete_unification method.
 

Friends

ostream & operator<< (ostream &, const Unifier &)
 

Detailed Description

Wrap up various applications of unificiation into a single class: all the unification you need to do happens here.

You may find yourself unifying Terms, Literals and so on. This puts it all in one place. The class is a function class with various overloaded operator() methods.

All the real work happens in the "complete_unification" method.

See the Wikipedia page. This is apparently due to Montelli and Montanari (1982). Looking at "An Efficient Unification Algorithm – yes, indeed it is. The algorithm as stated in the paper is nondeterministic, and apparently you get a bunch of different outcomes depending on the details of the implementation.

So: this one uses a queue, taking something from the end and placing any results at the beginning.

Note that some modifications have to be made compared with the paper's presentation, because the method used to make substitutions takes immediate effect. As a result, substitutions get removed by the Delete rule, so you might as well remove them immediately. Also, when substituting x=? you don't need to check whether x appears in the other equations.

Definition at line 83 of file Unifier.hpp.

Constructor & Destructor Documentation

◆ Unifier() [1/2]

Unifier::Unifier ( )
inline

There isn't really much to initialize.

Definition at line 102 of file Unifier.hpp.

102: s(), to_do() {}
deque< UPair > to_do
Queue used by complete_unification method.
Definition Unifier.hpp:92
Substitution s
Build the resulting substitution here.
Definition Unifier.hpp:88

◆ Unifier() [2/2]

Unifier::Unifier ( const Unifier & )
delete

You really only need one Unifier!

As always, copying is a bad idea so let the compiler help you out.

Member Function Documentation

◆ backtrack()

void Unifier::backtrack ( )

Apply the backtracking process to the substitution that has been constructed.

Definition at line 134 of file Unifier.cpp.

134 {
135 s.backtrack();
136 s.clear();
137}
void backtrack() const
Remove a substitution everywhere.
void clear()
Clear a substitution.

◆ complete_unification()

UnificationOutcome Unifier::complete_unification ( )
private

Implementation of unification: all the real work happens here.

Definition at line 72 of file Unifier.cpp.

72 {
73 s.clear();
74 while (to_do.size() > 0) {
75 // Get the next thing from the queue and split it up.
76 UPair upair(to_do.front());
77 Term* t1(upair.first);
78 Term* t2(upair.second);
79 // Make sure you do this! Many long debugging sessions
80 // await if you ignore my advice.
81 t1 = t1->skip_leading_variables();
82 t2 = t2->skip_leading_variables();
83 to_do.pop_front();
84 // Work out exactly what everything is.
85 bool t1_is_fun = t1->subbed_is_function();
86 bool t2_is_fun = t2->subbed_is_function();
87 bool t1_is_var = t1->subbed_is_variable();
88 bool t2_is_var = t2->subbed_is_variable();
89 Variable* t1v = nullptr;
90 if (t1_is_var)
91 t1v = t1->get_v()->subbed_variable();
92
93 // Delete
94 if (t1->subbed_equal(t2)) {
95 continue;
96 }
97 // Swap
98 if (t1_is_fun && t2_is_var) {
99 to_do.push_back(UPair(t2, t1));
100 continue;
101 }
102 // Occurs
103 if (t1_is_var && t2_is_fun && t2->contains_variable(t1v)) {
104 backtrack();
105 return UnificationOutcome::OccursFail;
106 }
107 // Eliminate
108 if (t1_is_var && !t2->contains_variable(t1v)) {
109 s.push_back(t1v, t2);
110 t1v->substitute(t2);
111 continue;
112 }
113 // Decompose/Conflict
114 if (t1_is_fun && t2_is_fun) {
115 // Conflict
116 if ((t1->get_subbed_f() != t2->get_subbed_f()) ||
117 (t1->get_subbed_arity() != t2->get_subbed_arity())) {
118 backtrack();
119 return UnificationOutcome::ConflictFail;
120 }
121 // Decompose
122 else {
123 size_t n_args = t1->arity();
124 for (size_t i = 0; i < n_args; i++) {
125 to_do.push_back(UPair((*t1)[i], (*t2)[i]));
126 }
127 continue;
128 }
129 }
130 }
131 return UnificationOutcome::Succeed;
132}
void push_back(Variable *, Term *)
Add a pair to a substitution.
General representation of terms.
Definition Term.hpp:62
void backtrack()
Apply the backtracking process to the substitution that has been constructed.
Definition Unifier.cpp:134
Basic representation of variables.
Definition Variable.hpp:58
Variable * subbed_variable() const
If the variable is unsubbed then return "this"; otherwise a pointer to the variable at the end of a c...
Definition Term.cpp:309
void substitute(Term *t)
Self-explanatory, but be careful!
Definition Variable.hpp:142

◆ get_substitution()

Substitution Unifier::get_substitution ( ) const
inline

Trivial get methods for the result.

Definition at line 116 of file Unifier.hpp.

116{ return s; }

◆ operator()() [1/4]

UnificationOutcome Unifier::operator() ( const Literal & l1,
const Literal & l2 )

Unification of Literals.

Parameters
l1Reference to first Literal
l2Reference to second Literal

Definition at line 59 of file Unifier.cpp.

60 {
61 if (!l1.is_compatible_with(&l2)) {
62 cerr << "ERROR" << ": ";
63 cerr << "You're trying to unify non-compatible literals." << endl;
64 cerr << "ERROR" << ": " << l1 << endl;
65 cerr << "ERROR" << ": " << l2 << endl;
66 }
67 const vector<Term*>& args1 = l1.get_args();
68 const vector<Term*>& args2 = l2.get_args();
69 return operator()(args1, args2);
70}
const vector< Term * > & get_args() const
Basic get method.
Definition Literal.hpp:83
bool is_compatible_with(const Literal *) const
Literals can only be unified if the polarity and actual predicate are the same.
Definition Literal.cpp:67
UnificationOutcome operator()(Term *, Term *)
Implementation of unification for a pair of Terms.
Definition Unifier.cpp:28

◆ operator()() [2/4]

UnificationOutcome Unifier::operator() ( const vector< Term * > & t1s,
const vector< Term * > & t2s )

The same as the main operator(), but you've already extracted the arguments for the things of interest into lists.

Parameters
t1sReference to vector of pointers to Terms
t2sReference to vector of pointers to Terms

Definition at line 34 of file Unifier.cpp.

35 {
36 if (t1s.size() != t2s.size())
37 return UnificationOutcome::ConflictFail;
38 to_do.clear();
39 auto i = t2s.begin();
40 for (Term* term1 : t1s) {
41 to_do.push_front(UPair(term1, *i));
42 i++;
43 }
44 return complete_unification();
45}
UnificationOutcome complete_unification()
Implementation of unification: all the real work happens here.
Definition Unifier.cpp:72

◆ operator()() [3/4]

UnificationOutcome Unifier::operator() ( Literal * l1,
Literal * l2 )

Unification of Literals.

Parameters
l1Pointer to first Literal
l2Pointer to second Literal

Definition at line 47 of file Unifier.cpp.

47 {
48 if (!l1->is_compatible_with(l2)) {
49 cerr << "ERROR" << ": ";
50 cerr << "You're trying to unify non-compatible literals." << endl;
51 cerr << "ERROR" << ": " << *l1 << endl;
52 cerr << "ERROR" << ": " << *l2 << endl;
53 }
54 const vector<Term*>& args1 = l1->get_args();
55 const vector<Term*>& args2 = l2->get_args();
56 return operator()(args1, args2);
57}

◆ operator()() [4/4]

UnificationOutcome Unifier::operator() ( Term * term1,
Term * term2 )

Implementation of unification for a pair of Terms.

See the Wikipedia page. This is apparently due to Montelli and Montanari (1982). Looking at "An Efficient Unification Algorithm – yes, indeed it is.

See also the documentation for complete_unification.

Parameters
term1Pointer to first term
term2Pointer to second term

Definition at line 28 of file Unifier.cpp.

28 {
29 to_do.clear();
30 to_do.push_front(UPair(term1, term2));
31 return complete_unification();
32}

◆ to_string()

string Unifier::to_string ( bool subbed = false) const
inline

Make a nice string representation.

Parameters
subbedUse substitutions if true.

Definition at line 164 of file Unifier.hpp.

164 {
165 return s.to_string(subbed);
166 }
string to_string(bool=false) const
Make a string representation.

Friends And Related Symbol Documentation

◆ operator<<

ostream & operator<< ( ostream & out,
const Unifier & u )
friend

Definition at line 157 of file Unifier.cpp.

157 {
158 out << u.to_string();
159 return out;
160}
string to_string(bool subbed=false) const
Make a nice string representation.
Definition Unifier.hpp:164

Member Data Documentation

◆ s

Substitution Unifier::s
private

Build the resulting substitution here.

Definition at line 88 of file Unifier.hpp.

◆ to_do

deque<UPair> Unifier::to_do
private

Queue used by complete_unification method.

Definition at line 92 of file Unifier.hpp.


The documentation for this class was generated from the following files: