forked from MarisaKirisame/first_order_logic_prover
/
knowledge_base.hpp
179 lines (179 loc) · 5.64 KB
/
knowledge_base.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#ifndef KNOWLEDGE_BASE_HPP
#define KNOWLEDGE_BASE_HPP
#include <list>
#include "definite_clause.hpp"
#include "substitution.hpp"
namespace first_order_logic
{
struct knowledge_base
{
std::vector< definite_clause > kb;
std::vector< atomic_sentence > known_facts;
template< typename ITER >
ITER matching_facts( const atomic_sentence & match, const substitution & sub, ITER result ) const
{
for ( auto i = known_facts.begin( ); i != known_facts.end( ); ++i )
{
const auto & sen = * i;
assert( static_cast< bool >( sen.data ) );
auto res = unify( match, sen, sub );
if ( res ) { * result = std::make_pair( sen, * res ); }
}
return result;
}
std::set< std::string > variable_name( )
{
std::set< std::string > ret;
auto extract =
[&]( const atomic_sentence & s )
{ s.cv( make_function_output_iterator( [&]( const term & t ){ ret.insert( t->name ); } ) ); };
for ( const definite_clause & dc : kb )
{
std::for_each( dc.premise.begin( ), dc.premise.end( ), extract );
extract( dc.conclusion );
}
return ret;
}
bool try_infer_forward(
const std::vector< atomic_sentence > & premise,
const atomic_sentence & conclusion,
const substitution & rename,
const atomic_sentence & query )
{
bool ret = false;
std::vector< atomic_sentence > new_known_facts;
substitution s;
std::vector< atomic_sentence > gp;
auto generate =
[&,this]( const auto & self, const substitution & sub )->void
{
if ( gp.size( ) == premise.size( ) ) { new_known_facts.push_back( sub( rename( conclusion ) ) ); }
else
{
this->matching_facts(
rename( premise[ gp.size( ) ] ),
sub,
make_function_output_iterator(
[&]( const std::pair< atomic_sentence, substitution > & p )
{
if ( ( new_known_facts.empty( ) ) || ( ! unify( new_known_facts.back( ), query ) ) )
{
gp.push_back( p.first );
self( self, p.second );
gp.pop_back( );
}
} ) );
}
};
generate( generate, s );
for ( const atomic_sentence & sen : new_known_facts )
{
if ( std::none_of(
known_facts.begin( ),
known_facts.end( ),
[&]( const atomic_sentence & s ){ return unify( sen, s ); } ) )
{
known_facts.push_back( sen );
ret = true;
}
}
return ret;
}
boost::optional< substitution > forward_chaining( const atomic_sentence & sen )
{
for ( const atomic_sentence & se : known_facts )
{
auto ret = unify( se, sen );
if ( ret ) { return ret; }
}
bool have_new_inference = true;
std::set< std::string > var_name = variable_name( );
while ( have_new_inference )
{
have_new_inference = false;
for ( const definite_clause & dc : kb )
{
assert( ! dc.premise.empty( ) );
substitution rename =
rename_variable(
dc.premise.begin( ),
dc.premise.end( ),
[&]( const std::string & v ){ return var_name.count( v ) == 0; },
[]( const std::string & n ){ return n + "_"; } );
have_new_inference = try_infer_forward( dc.premise, dc.conclusion, rename, sen ) || have_new_inference;
auto ret = unify( known_facts.back( ), sen );
if ( ret ) { return ret; }
}
}
return boost::optional< substitution >( );
}
boost::optional< substitution > backward_chaining( const atomic_sentence & sen )
{
for ( const atomic_sentence & se : known_facts )
{
auto ret = unify( se, sen );
if ( ret ) { return ret; }
}
if ( known_facts.empty( ) ) { return boost::optional< substitution >( ); }
std::set< std::string > var_name = variable_name( );
std::map< atomic_sentence, std::vector< std::vector< atomic_sentence > > > requiring_fact;
bool progress = true;
auto try_add =
[&]( const atomic_sentence & s )
{
if ( requiring_fact.count( s ) == 0 )
{
std::vector< std::vector< atomic_sentence > > deduct_from;
for ( const definite_clause & dc : kb )
{
assert( ! dc.premise.empty( ) );
substitution rename =
rename_variable(
dc.premise.begin( ),
dc.premise.end( ),
[&]( const std::string & v ){ return var_name.count( v ) == 0; },
[]( const std::string & n ){ return n + "_"; } );
auto ret = unify( rename( dc.conclusion ), s );
if ( ret )
{
std::vector< atomic_sentence > tem;
for ( const atomic_sentence & se : dc.premise )
{ tem.push_back( ( *ret )( rename( se ) ) ); }
deduct_from.push_back( tem );
}
}
requiring_fact.insert( std::make_pair( s, deduct_from ) );
progress = true;
}
};
try_add( sen );
while ( progress )
{
progress = false;
auto ret = unify( known_facts.back( ), sen );
if ( ret ) { return ret; }
std::vector< atomic_sentence > add;
for ( const std::pair< atomic_sentence, std::vector< std::vector< atomic_sentence > > > & p :
requiring_fact )
{
for ( const std::vector< atomic_sentence > & vec : p.second )
{
substitution rename =
rename_variable(
vec.begin( ),
vec.end( ),
[&]( const std::string & v ){ return var_name.count( v ) == 0; },
[]( const std::string & n ){ return n + "_"; } );
progress = try_infer_forward( vec, p.first, rename, sen ) || progress;
auto ret = unify( known_facts.back( ), sen );
if ( ret ) { return ret; }
std::copy( vec.begin( ), vec.end( ), std::back_inserter( add ) );
}
}
std::for_each( add.begin( ), add.end( ), try_add );
}
return boost::optional< substitution >( );
}
};
}
#endif // KNOWLEDGE_BASE_HPP