OpenCog Framework  Branch: master, revision 6f0b7fc776b08468cf1b74aa9db028f387b4f0c0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
Instantiator.cc
Go to the documentation of this file.
1 /*
2  * Instantiator.cc
3  *
4  * Copyright (C) 2009, 2014, 2015 Linas Vepstas
5  *
6  * Author: Linas Vepstas <linasvepstas@gmail.com> January 2009
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Affero General Public License v3 as
10  * published by the Free Software Foundation and including the exceptions
11  * at http://opencog.org/wiki/Licenses
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Affero General Public License
19  * along with this program; if not, write to:
20  * Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23 
28 
29 #include "Instantiator.h"
30 
31 using namespace opencog;
32 
34 {
35  Type t = expr->getType();
36 
37  // Must not explore the insides of a QuoteLink.
38  if (QUOTE_LINK == t)
39  return Handle(expr);
40 
41  LinkPtr lexpr(LinkCast(expr));
42  if (not lexpr)
43  {
44  // If were are here, we are a Node.
45  if (VARIABLE_NODE != t)
46  return Handle(expr);
47 
48  // If we are here, we found a variable. Look it up. Return a
49  // grounding if it has one, otherwise return the variable
50  // itself.
51  std::map<Handle,Handle>::const_iterator it = _vmap->find(expr);
52  if (_vmap->end() == it) return Handle(expr);
53 
54  // Not so fast, pardner. VariableNodes can be grounded by
55  // links, and those links may be executable. In that case,
56  // we have to execute them.
57 
58  // halt infinite regress
59  if (_halt)
60  return Handle(expr);
61 
62  _halt = true;
63  Handle hgnd(walk_tree(it->second));
64  _halt = false;
65  return hgnd;
66  }
67 
68  // If we are here, then we have a link. Walk it. In general,
69  // links may contain both bound variables, and also free variables.
70  // We must be careful to subtitute only for free variables, and
71  // never for bound ones.
72  //
73  // Reduce PutLinks.
74  if (PUT_LINK == t)
75  {
76  PutLinkPtr ppp(PutLinkCast(expr));
77 
78  // PutLinks always have arity two. There are NO free vars in
79  // the body of the PutLink. If there are free vars, they are
80  // in the argument. Subsitute for them. Do NOT execute the
81  // body until after the beta-reduction has been done.
82  const HandleSeq& oset = lexpr->getOutgoingSet();
83  Handle gargs = walk_tree(oset[1]);
84  if (gargs != oset[1])
85  {
86  HandleSeq groset;
87  groset.push_back(oset[0]);
88  groset.push_back(gargs);
89  ppp = createPutLink(groset);
90  }
91  // Step one: beta-reduce.
92  Handle red = ppp->reduce();
93  // Step two: execute the resulting body.
94  return walk_tree(red);
95  }
96 
97  // If we are here, we assume that any/all variables that are in
98  // the outgoing set are free variables. Substitute the ground
99  // values for them. Do this by tree-walk.
100  HandleSeq oset_results;
101  for (const Handle& h : lexpr->getOutgoingSet())
102  {
103  Handle hg = walk_tree(h);
104  // It could be a NULL handle if it's deleted... Just skip
105  // over it. We test the pointer here, not the uuid, since
106  // the uuid's are all Handle::UNDEFINED until we put them
107  // into the atomspace.
108  if (NULL != hg)
109  oset_results.push_back(hg);
110  }
111 
112  // Handle DeleteLink's before general FunctionLink's; they
113  // work differently.
114  if (DELETE_LINK == t)
115  {
116  for (const Handle& h: oset_results)
117  if (VARIABLE_NODE != h->getType())
118  _as->remove_atom(h, true);
119 
120  return Handle::UNDEFINED;
121  }
122 
123  // Fire execution links, if found.
124  if (classserver().isA(t, FUNCTION_LINK))
125  {
126  // ExecutionOutputLinks are not handled by the factory below.
127  // This is due to a circular shared-libarary dependency.
128  if (EXECUTION_OUTPUT_LINK == t)
129  {
130  // The atoms being created above might not all be in the
131  // atomspace, just yet. Because we have no clue what the
132  // ExecutionOutputLink might do (its a black box), we had
133  // best put them there now. In particular, the black box
134  // may want to look at the atom TV's, and for that, they
135  // MUST be fetched from the atomspace, since only the
136  // atomspace knows the correct TV values.
137  //
138  // The problem here is that the insertion leaves garbage
139  // intermediate-result atoms littering the atomspace, with
140  // no effective way of removing them. XXX This needs fixing.
141  // Again, some kind of monad solution. XXX FIXME later.
142  //
143  // Just as well, because it seems the scheme (and python)
144  // bindings get tripped up by the UUID==-1 of uninserted atoms.
145  // XXX Well, this arguably means that scheme and python are
146  // broken.
147  size_t sz = oset_results.size();
148  for (size_t i=0; i< sz; i++)
149  oset_results[i] = _as->add_atom(oset_results[i]);
150 
152  return eolp->execute(_as);
153  }
154 
155  // This throws if it can't figure out the schema ...
156  // Let the throw pass right on up the stack.
157  Handle hl(FunctionLink::factory(t, oset_results));
159  return flp->execute(_as);
160  }
161 
162  // If there is a GetLink, we have to perform the get, and replace
163  // it with the results of the get. The get is implemented with the
164  // PatternLink::satisfy() method.
165  if (GET_LINK == t)
166  {
167  size_t sz = oset_results.size();
168  for (size_t i=0; i< sz; i++)
169  oset_results[i] = _as->add_atom(oset_results[i]);
170 
171  LinkPtr lp = createLink(GET_LINK, oset_results);
172 
173  return satisfying_set(_as, Handle(lp));
174  }
175 
176  // Now create a duplicate link, but with an outgoing set where
177  // the variables have been substituted by their values.
178  return Handle(createLink(t, oset_results, expr->getTruthValue()));
179 }
180 
195  const std::map<Handle, Handle> &vars)
196 {
197  // throw, not assert, because this is a user error ...
198  if (Handle::UNDEFINED == expr)
199  throw InvalidParamException(TRACE_INFO,
200  "Asked to ground a null expression");
201 
202  _vmap = &vars;
203 
204  // The returned handle is not yet in the atomspace. Add it now.
205  // We do this here, instead of in walk_tree(), because adding
206  // atoms to the atomspace is an expensive process. We can save
207  // some time by doing it just once, right here, in one big batch.
208  // A null pointer means that we hit
209  Handle gnd = walk_tree(expr);
210  if (NULL != gnd)
211  return _as->add_atom(gnd);
212  return gnd;
213 }
214 
215 /* ===================== END OF FILE ===================== */
static PutLinkPtr PutLinkCast(const Handle &h)
Definition: PutLink.h:85
#define createLink
Definition: Link.h:269
const std::map< Handle, Handle > * _vmap
Definition: Instantiator.h:46
std::vector< Handle > HandleSeq
a list of handles
Definition: Handle.h:246
#define createExecutionOutputLink
Type getType() const
Definition: Atom.h:197
std::shared_ptr< Link > LinkPtr
Definition: Atom.h:53
std::shared_ptr< FunctionLink > FunctionLinkPtr
Definition: FunctionLink.h:78
ClassServer & classserver(ClassServerFactory *=ClassServer::createInstance)
Definition: ClassServer.cc:159
#define createPutLink
Definition: PutLink.h:91
static const Handle UNDEFINED
Definition: Handle.h:77
Handle satisfying_set(AtomSpace *, const Handle &)
Definition: Satisfier.cc:86
static FunctionLinkPtr FunctionLinkCast(const Handle &h)
Definition: FunctionLink.h:79
Handle instantiate(const Handle &expr, const std::map< Handle, Handle > &vars)
bool remove_atom(Handle h, bool recursive=false)
Definition: AtomSpace.cc:344
static LinkPtr LinkCast(const Handle &h)
Definition: Link.h:263
std::shared_ptr< ExecutionOutputLink > ExecutionOutputLinkPtr
TruthValuePtr getTruthValue()
Definition: Atom.cc:104
Handle walk_tree(const Handle &tree)
Definition: Instantiator.cc:33
unsigned short Type
type of Atoms, represented as short integer (16 bits)
Definition: types.h:40
std::shared_ptr< PutLink > PutLinkPtr
Definition: PutLink.h:84
Handle add_atom(AtomPtr atom, bool async=false)
Definition: AtomSpace.cc:100