OpenCog Framework  Branch: master, revision 6f0b7fc776b08468cf1b74aa9db028f387b4f0c0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
PatternMatchEngine.cc
Go to the documentation of this file.
1 /*
2  * PatternMatchEngine.cc
3  *
4  * Copyright (C) 2008,2009,2011,2014,2015 Linas Vepstas
5  *
6  * Author: Linas Vepstas <linasvepstas@gmail.com> February 2008
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 
24 #include <opencog/util/oc_assert.h>
25 #include <opencog/util/Logger.h>
29 #include <opencog/atomspace/Link.h>
30 #include <opencog/atomspace/Node.h>
31 
32 #include "PatternMatchEngine.h"
33 
34 using namespace opencog;
35 /* ======================================================== */
44 /* ======================================================== */
45 
46 // To enable debug print you must
47 //
48 // 1. Uncomment #define DEBUG below
49 //
50 // 2. Comment out #ifdef DEBUG and #endif in PatternMatchEngine.h in
51 // order to have perm_count and perm_count_stack defined.
52 // #define DEBUG
53 #ifdef WIN32
54 #ifdef DEBUG
55  #define dbgprt printf
56 #else
57  // something better?
58  #define dbgprt
59 #endif
60 #else
61 #ifdef DEBUG
62  #define dbgprt(f, varargs...) printf(f, ##varargs)
63 #else
64  #define dbgprt(f, varargs...)
65 #endif
66 #endif
67 
68 static inline bool prt(const Handle& h)
69 {
70  std::string str = h->toShortString();
71  printf ("%s\n", str.c_str());
72  return false;
73 }
74 
75 static inline void prtmsg(const char * msg, const Handle& h)
76 {
77 #ifdef DEBUG
78  if (h == Handle::UNDEFINED) {
79  printf ("%s (invalid handle)\n", msg);
80  return;
81  }
82  std::string str = h->toShortString();
83  printf ("%s %s\n", msg, str.c_str());
84 #endif
85 }
86 
87 /* ======================================================== */
88 
89 // At this time, we don't want groundings where variables ground
90 // themselves. However, there is a semi-plausible use-case for
91 // this, see https://github.com/opencog/opencog/issues/1092
92 // Undefine this to experiment. See also the unit tests.
93 #define NO_SELF_GROUNDING 1
94 
95 /* Reset the current variable grounding to the last grounding pushed
96  * onto the stack. */
97 #ifdef DEBUG
98  #define POPSTK(stack,soln) { \
99  OC_ASSERT(not stack.empty(), \
100  "Unbalanced stack " #stack); \
101  soln = stack.top(); \
102  stack.pop(); \
103  }
104 #else
105  #define POPSTK(stack,soln) { \
106  soln = stack.top(); \
107  stack.pop(); \
108  }
109 #endif
110 
111 /* ======================================================== */
112 
118  const Handle& hg)
119 {
120  in_quote = true;
121  LinkPtr lp(LinkCast(ptm->getHandle()));
122  if (1 != lp->getArity())
123  throw InvalidParamException(TRACE_INFO,
124  "QuoteLink has unexpected arity!");
125  bool ma = tree_compare(ptm->getOutgoingTerm(0), hg, CALL_QUOTE);
126  in_quote = false;
127  return ma;
128 }
129 
130 /* ======================================================== */
131 
136  const Handle& hg)
137 {
138 #ifdef NO_SELF_GROUNDING
139  // But... if handle hg happens to also be a bound var,
140  // then its a mismatch.
141  if (_varlist->varset.end() != _varlist->varset.find(hg)) return false;
142 #endif
143 
144  // If we already have a grounding for this variable, the new
145  // proposed grounding must match the existing one. Such multiple
146  // groundings can occur when traversing graphs with loops in them.
147  try
148  {
149  Handle gnd(var_grounding.at(hp));
150  if (Handle::UNDEFINED != gnd)
151  return (gnd == hg);
152  }
153  catch(...) { }
154 
155  // VariableNode had better be an actual node!
156  // If it's not then we are very very confused ...
157  NodePtr np(NodeCast(hp));
158  OC_ASSERT (NULL != np,
159  "ERROR: expected variable to be a node, got this: %s\n",
160  hp->toShortString().c_str());
161 
162 #ifdef NO_SELF_GROUNDING
163  // Disallow matches that contain a bound variable in the
164  // grounding. However, a bound variable can be legitimately
165  // grounded by a free variable (because free variables are
166  // effectively constant literals, during the pattern match.
167  if (VARIABLE_NODE == hg->getType() and
168  _varlist->varset.end() != _varlist->varset.find(hg))
169  {
170  return false;
171  }
172 #endif
173 
174  // Else, we have a candidate grounding for this variable.
175  // The variable_match() callback may implement some tighter
176  // variable check, e.g. to make sure that the grounding is
177  // of some certain type.
178  if (not _pmc.variable_match (hp, hg)) return false;
179 
180  // Make a record of it.
181  dbgprt("Found grounding of variable:\n");
182  prtmsg("$$ variable: ", hp);
183  prtmsg("$$ ground term: ", hg);
184  if (hp != hg) var_grounding[hp] = hg;
185  return true;
186 }
187 
188 /* ======================================================== */
189 
200 {
201  // prtmsg("Compare atom to itself:\n", hp);
202 
203 #ifdef NO_SELF_GROUNDING
204 #if THIS_CANT_BE_RIGHT
205  // Bound but quoted variables cannot be solutions to themselves.
206  // huh? whaaaat?
207  if (not in_quote or
208  (in_quote and
209  (VARIABLE_NODE != tp or
210  _varlist->varset.end() == _varlist->varset.find(hp))))
211  {
212  if (hp != hg) var_grounding[hp] = hg;
213  }
214 #endif // THIS_CANT_BE_RIGHT
215 #endif
216  return true;
217 }
218 
219 /* ======================================================== */
220 
223  const Handle& hg)
224 {
225  // Call the callback to make the final determination.
226  bool match = _pmc.node_match(hp, hg);
227  if (match)
228  {
229  dbgprt("Found matching nodes\n");
230  prtmsg("# pattern: ", hp);
231  prtmsg("# match: ", hg);
232  if (hp != hg) var_grounding[hp] = hg;
233  }
234  return match;
235 }
236 
237 /* ======================================================== */
238 
242  const Handle& hg,
243  const LinkPtr& lp,
244  const LinkPtr& lg)
245 {
246  const PatternTermSeq &osp = ptm->getOutgoingSet();
247  const HandleSeq &osg = lg->getOutgoingSet();
248 
249 // size_t oset_sz = osp.size();
250 // if (oset_sz != osg.size()) return false;
251 
252  size_t osg_size = osg.size();
253  size_t osp_size = osp.size();
254  size_t max_size = std::max(osg.size(), osp.size());
255 
256  // The recursion step: traverse down the tree.
257  // In principle, we could/should push the current groundings
258  // onto the stack before recursing, and then pop them off on
259  // return. Failure to do so could leave some bogus groundings,
260  // sitting around, i.e. groundings that were found during
261  // recursion but then discarded due to a later mis-match.
262  //
263  // In practice, I was unable to come up with any test case
264  // where this mattered; any bogus groundings eventually get
265  // replaced by valid ones. Thus, we save some unknown amount
266  // of cpu time by simply skipping the push & pop here.
267  //
268  depth ++;
269 
270  bool match = true;
271  for (size_t i=0; i<max_size; i++)
272  {
273  bool tc = false;
274  if (i < osp_size and i < osg_size)
275  tc = tree_compare(osp[i], osg[i], CALL_UNORDER);
276 
277  else if (i < osp_size)
279 
281 
282  if (not tc)
283  {
284  match = false;
285  break;
286  }
287  }
288 
289  depth --;
290  dbgprt("tree_comp down link match=%d\n", match);
291 
292  if (not match) return false;
293 
294  // If we've found a grounding, lets see if the
295  // post-match callback likes this grounding.
296  match = _pmc.post_link_match(lp, lg);
297  if (not match) return false;
298 
299  // If we've found a grounding, record it.
300  const Handle &hp = ptm->getHandle();
301  if (hp != hg) var_grounding[hp] = hg;
302 
303  return true;
304 }
305 
306 /* ======================================================== */
307 
316  const Handle& hg,
317  const LinkPtr& lp,
318  const LinkPtr& lg)
319 {
320  const Handle& hp = ptm->getHandle();
321  const PatternTermSeq &osp = ptm->getOutgoingSet();
322 
323  // _choice_state lets use resume where we last left off.
324  size_t iend = osp.size();
325  bool fresh = false;
326  size_t icurr = curr_choice(ptm, hg, fresh);
327  if (fresh) choose_next = false; // took a step, clear the flag
328 
329  dbgprt("tree_comp resume choice search at %zu of %zu of term=%s, "
330  "choose_next=%d\n",
331  icurr, iend, ptm->toString().c_str(), choose_next);
332 
333  // XXX This is almost surely wrong... if there are two
334  // nested choice links, then this will hog the steps,
335  // and the deeper choice will fail.
336  if (choose_next)
337  {
338  icurr++;
339  choose_next = false; // we are taking a step, so clear the flag.
340  }
341 
342  while (icurr<iend)
343  {
344  solution_push();
345  const PatternTermPtr& hop = osp[icurr];
346 
347  dbgprt("tree_comp or_link choice %zu of %zu\n", icurr, iend);
348 
349  bool match = tree_compare(hop, hg, CALL_CHOICE);
350  if (match)
351  {
352  // If we've found a grounding, lets see if the
353  // post-match callback likes this grounding.
354  match = _pmc.post_link_match(lp, lg);
355  if (match)
356  {
357  // Even the stack, *without* erasing the discovered grounding.
358  solution_drop();
359 
360  // If the grounding is accepted, record it.
361  if (hp != hg) var_grounding[hp] = hg;
362 
363  _choice_state[Choice(ptm, hg)] = icurr;
364  return true;
365  }
366  }
367  solution_pop();
368  choose_next = false; // we are taking a step, so clear the flag.
369  icurr++;
370  }
371 
372  // If we are here, we've explored all the possibilities already
373  _choice_state.erase(Choice(ptm, hg));
374  return false;
375 }
376 
380  const Handle& hg,
381  bool& fresh)
382 {
383  size_t istart;
384  try { istart = _choice_state.at(Choice(ptm, hg)); }
385  catch(...) { istart = 0; fresh = true; }
386  return istart;
387 }
388 
390  const Handle& hg)
391 {
392 #if USE_AT
393  bool have = true;
394  try { _choice_state.at(Choice(ptm, hg)); }
395  catch(...) { have = false;}
396  return have;
397 #else
398  return 0 < _choice_state.count(Choice(ptm, hg));
399 #endif
400 }
401 
402 /* ======================================================== */
403 #ifdef DEBUG
404 static int facto (int n) { return (n==1)? 1 : n * facto(n-1); };
405 #endif
406 
419 /*****************************************************************
420 
421 How do unordered links work?
422 ----------------------------
423 This is complicted, so we write it out. When ascending from below (i.e.
424 from do_term_up()), unordered links may be found in two different
425 places: The parent term may be unordered, or the parent link may hold
426 another link (a sibling to us) that is unordered. Traversal needs to
427 handle both cases. Thus, the upwards-movement methods (do_term_sup(),
428 explore_up_branches(), etc.) are incapable of discovering unordered links,
429 as they cannot "see" the siblings. Siblings can only be found during
430 tree-compare, moving downwards. Thus, tree_compare must do a lot of
431 heavy lifting.
432 
433 When comparing trees downwards, we have two situations we may be in:
434 we may be asked to compare things exactly like last time, or we may be
435 asked to try out the next permutation. We need to report back two bits
436 of state: whether or not we found a match, and whether or not we have
437 more possibilities to explore. Our behavior is thus controlled by this
438 third bit, as well as what happened below us.
439 
440 The correct actions to take are best explored by truth tables: the
441 settings of the take_step and have_more flags on entry, and what to
442 do after running tree_compare downwards. These are handled by two
443 truth tables.
444 
445 The topmost routine to call tree_compare must *always* set have_more=F
446 and take_step=T before calling tree compare. This will cause
447 tree_compare to advance to the next matching permuation, or to run until
448 all permuations are exhausted, and no match was found.
449 
450 
451 Flag settings upon entry
452 ------------------------
453 
454  take have
455 case step more Comments / Action to be Taken
456 ---- ---- ---- -----------------------------
457  A T T Impossible, Who set have_more? Who set take_step?
458  B T F Normal entry: we are first unordered link to be hit
459  during downward travesal. Proceed using the truth
460  table below.
461  C F T We are not the first unorder. Someone ran before us.
462  If we are in the very first permuation, (i.e. we are
463  entering for the first time) we must call downwards.
464  If this returns a mismatch, we must step until we
465  find a match, or until we exhaust all permuatations.
466  See next table for what to return: we return cases
467  5, 7 or 8.
468  If we are not the first permutation, we could just
469  return T, because that is what we did last time.
470  i.e. we are told to not take a step, so we don't,
471  and we know a-priori last time were were here, we
472  must have returned a match. Thus, we can return
473  case 5 below. We cannot return case 7 because we
474  can't know what std::next_perm returns.
475  (See however, footnote below).
476  If we hold an evaluatable, we must call down.
477  D F F Perform same as C above.
478 
479 Footnote: case C: Well, thr reasoning there is almost riht, but not
480 quite. If the unordered link contains a variable, and it is also not in
481 the direct line of exploration (i.e. its grounding is NOT recorded)
482 then its truthiness holds only for a grounding that no longer exists.
483 Thus, for case C, it is safer to always check.
484 
485 However, by the above reasoning: if the grounding wasn't recorded
486 (because the link is not in the recursion path) then the permuation
487 should not be recorded either. It should start with a permutation from
488 nothing. XXX FIXME ... except we have no test case that illustrates
489 this failure mode. It would require a peer unordered link that takes
490 a different order when the parent changes. Perhaps unordered links
491 nested inside a ChoiceLink would trigger this?
492 
493 If case B was encountered on entry, we call downwards ourselves, and
494 then report back, according to the truth table below.
495 
496  returned result flags
497  take have got
498 case step more match Comments / Action to tbe Taken
499 ---- ---- ---- ---- ------------------------------
500  1 T T T Impossible, error: who set have_more w/o
501  taking step??
502  2 T T F ditto
503  3 T F T We have no unordered links below us; we are at
504  the bottom. If there had been unordered links,
505  they would have cleared the take_step flag. The
506  match we detected is the same match the last
507  time we were here. So we take a step, call
508  down again, and keep stepping until there is a
509  match or until all permuations are exhausted.
510  If match, we return: take_step=F,
511  have_more = result of std::next_perm
512  (we return case 5 or 7)
513  If exhaust, we return take_step=F, have_more=F
514  (we return case 8)
515 
516  4 T F F If we are not holding any evaluatable links,
517  then this is impossible, as last time we were
518  here, we returned T. If we are holding
519  evaluatable links, then one of them changed its
520  mind. Oh well. Take a step, proceed as in case 3.
521 
522  5 F T T Someone below us took a step. Do nothing.
523  Return case 5 flags.
524  6 F T F Impossible; link that took the step should have
525  stepped until match or exhastion.
526  7 F F T Unusual; its the last match for a lower unordered
527  link. We report the match. We do not take a
528  step; we do set the have_more flag to indicate
529  that we ourselves still have more. i.e We return
530  case 5 flags.
531  8 F F F Typical; a lower unord link ran to exhaustion,
532  and got nada. So *we* take a step, and call
533  downwards again. We keep going till match or till
534  exhaustion. If there's a match, we expect to see
535  the case 5 flags, so we halt and return. If we
536  exhaust, we return case 8.
537 
538 The above assumes that the curr_perm() method always returns either
539 the current permuation, or it returns a fresh permuation. If it returned
540 a fresh permuation, this counts as "taking a step", so we need to know
541 this.
542 
543 Notice that these rules never pushed of popped the have-more stack.
544 The have-more stack is only pushed/popped by other branchpoints, before
545 they call compare_tree.
546 
547 ******************************************************************/
548 
550  const Handle& hg,
551  const LinkPtr& lp,
552  const LinkPtr& lg)
553 {
554  const Handle& hp = ptm->getHandle();
555  const HandleSeq& osg = lg->getOutgoingSet();
556  const PatternTermSeq& osp = ptm->getOutgoingSet();
557 // size_t arity = osp.size();
558  size_t osg_size = osg.size();
559  size_t osp_size = osp.size();
560  size_t max_size = std::max(osg.size(), osp.size());
561 
562  // They've got to be the same size, at the least!
563 // if (osg.size() != arity) return false;
564 
565  // Test for case A, described above.
566  OC_ASSERT (not (take_step and have_more),
567  "Impossible situation! BUG!");
568 
569  // _perm_state lets use resume where we last left off.
570  bool fresh = false;
571  Permutation mutation = curr_perm(ptm, hg, fresh);
572  if (fresh) take_step = false; // took a step, clear the flag.
573 
574  // Cases C and D fall through.
575  // If we are here, we've got possibilities to explore.
576 #ifdef DEBUG
577  int num_perms = facto(mutation.size());
578  dbgprt("tree_comp resume unordered search at %d of %d of term=%s "
579  "take_step=%d have_more=%d\n",
580  perm_count[Unorder(ptm, hg)], num_perms, ptm->toString().c_str(),
582 #endif
583  do
584  {
585  dbgprt("tree_comp explore unordered perm %d of %d of term=%s\n",
586  perm_count[Unorder(ptm, hg)], num_perms,
587  ptm->toString().c_str());
588 
589  solution_push();
590  bool match = true;
591  for (size_t i=0; i<max_size; i++)
592  {
593  bool tc = false;
594  if (i < osp_size and i < osg_size)
595  tc = tree_compare(mutation[i], osg[i], CALL_UNORDER);
596 
597  else if (i < osp_size)
598  tc = tree_compare(mutation[i], Handle::UNDEFINED, CALL_UNORDER);
599 
601 
602  if (not tc)
603  {
604  match = false;
605  break;
606  }
607  }
608 
609  // Check for cases 1&2 of description above.
610  // The step-next may have been taken by someone else, in the
611  // tree_compare immediate above.
612  OC_ASSERT(not (take_step and have_more),
613  "This shouldn't happen. Impossible situation! BUG!");
614 
615  // Handle cases 3&4 of the description above. Seems wisest
616  // to do this before post_link_match() !??
617  if (take_step and not have_more)
618  {
619  OC_ASSERT(match or (0 < _pat->evaluatable_holders.count(hp)),
620  "Impossible: should have matched!");
621  goto take_next_step;
622  }
623 
624  // If we are here, then take_step is false, because
625  // cases 1,2,3,4 already handled above.
626  // Well, actually, this can happen, if we are not careful
627  // to manage the have_more flag on a stack.
628 // OC_ASSERT(match or not have_more or 1==num_perms,
629 // "Impossible: case 6 happened!");
630 
631  if (match)
632  {
633  // If we've found a grounding, lets see if the
634  // post-match callback likes this grounding.
635  match = _pmc.post_link_match(lp, lg);
636  if (match)
637  {
638  // Even the stack, *without* erasing the discovered grounding.
639  solution_drop();
640 
641  // If the grounding is accepted, record it.
642  if (hp != hg) var_grounding[hp] = hg;
643 
644  // Handle case 5&7 of description above.
645  have_more = true;
646  dbgprt("Good permutation %d for term=%s have_more=%d\n",
647  perm_count[Unorder(ptm, hg)], ptm->toString().c_str(),
648  have_more);
649  _perm_state[Unorder(ptm, hg)] = mutation;
650  return true;
651  }
652  }
653  // If we are here, we are handling case 8.
654  dbgprt("Above permuation %d failed term=%s\n",
655  perm_count[Unorder(ptm, hg)], ptm->toString().c_str());
656 
657 take_next_step:
658  take_step = false; // we are taking a step, so clear the flag.
659  have_more = false; // start with a clean slate...
660  solution_pop();
661 #ifdef DEBUG
662  perm_count[Unorder(ptm, hg)] ++;
663 #endif
664  } while (std::next_permutation(mutation.begin(), mutation.end()));
665 
666  // If we are here, we've explored all the possibilities already
667  dbgprt("Exhausted all permuations of term=%s\n", ptm->toString().c_str());
668  _perm_state.erase(Unorder(ptm, hg));
669  have_more = false;
670  return false;
671 }
672 
678  const Handle& hg,
679  bool& fresh)
680 {
681  Permutation perm;
682  try { perm = _perm_state.at(Unorder(ptm, hg)); }
683  catch(...)
684  {
685 #ifdef DEBUG
686  dbgprt("tree_comp fresh start unordered link term=%s\n",
687  ptm->toString().c_str());
688  perm_count[Unorder(ptm, hg)] = 0;
689 #endif
690  perm = ptm->getOutgoingSet();
691  sort(perm.begin(), perm.end());
692  fresh = true;
693  }
694  return perm;
695 }
696 
700  const Handle& hg)
701 {
702  try { _perm_state.at(Unorder(ptm, hg)); }
703  catch(...) { return false; }
704  return true;
705 }
706 
708 {
709  perm_stack.push(_perm_state);
710 #ifdef DEBUG
711  perm_count_stack.push(perm_count);
712 #endif
713 }
714 
716 {
718 #ifdef DEBUG
719  POPSTK(perm_count_stack, perm_count);
720 #endif
721 }
722 
723 /* ======================================================== */
761  const Handle& hg,
762  Caller caller)
763 {
764  const Handle& hp = ptm->getHandle();
765 
766  // This could happen when the arity of the two hypergraphs are different.
767  // It's clearly a mismatch so we should always return false here unless
768  // we are looking for a non-exact match
769  if (Handle::UNDEFINED == hp or Handle::UNDEFINED == hg)
770  return _pmc.fuzzy_match(hp, hg);
771 
772  // If the pattern link is a quote, then we compare the quoted
773  // contents. This is done recursively, of course. The QuoteLink
774  // must have only one child; anything else beyond that is ignored
775  // (as its not clear what else could possibly be done).
776  Type tp = hp->getType();
777  if (not in_quote and QUOTE_LINK == tp)
778  return quote_compare(ptm, hg);
779 
780  // Handle hp is from the pattern clause, and it might be one
781  // of the bound variables. If so, then declare a match.
782  if (not in_quote and _varlist->varset.end() != _varlist->varset.find(hp))
783  return variable_compare(hp, hg);
784 
785  // If they're the same atom, then clearly they match.
786  // ... but only if hp is a constant i.e. contains no bound variables)
787  //
788  // If the pattern contains atoms that are evaluatable i.e. GPN's
789  // then we must fall through, and let the tree comp mechanism
790  // find and evaluate them. That's for two reasons: (1) because
791  // evaluation may have side-effects (e.g. send a message) and
792  // (2) evaluation may depend on external state. These are
793  // typically used to implement behavior trees, e.g SequenceUTest
794  if ((hp == hg) and not is_evaluatable(hp))
795  return self_compare(hp);
796 
797  // If both are nodes, compare them as such.
798  NodePtr np(NodeCast(hp));
799  NodePtr ng(NodeCast(hg));
800  if (np and ng)
801  return node_compare(hp, hg);
802 
803  // If they're not both are links, then it is clearly a mismatch.
804  LinkPtr lp(LinkCast(hp));
805  LinkPtr lg(LinkCast(hg));
806  if (not (lp and lg)) return _pmc.fuzzy_match(hp, hg);
807 
808 #ifdef NO_SELF_GROUNDING
809  // The proposed grounding must NOT contain any bound variables!
810  // .. unless they are quoted in the pattern, in which case they
811  // are allowed... well, not just allowed, but give the right
812  // answer. The below checks for this case. The check is not
813  // entirely correct though; there are some weird corner cases
814  // where a variable may appear quoted in the pattern, but then
815  // be in the wrong spot entirely in the proposed grounding, and
816  // so should not have been allowed.
817  // XXX FIXME For now, we punt on this... a proper fix would be
818  // ... hard, as we would have to line up the location of the
819  // quoted and the unquoted parts.
821  {
822  for (Handle vh: _varlist->varset)
823  {
824  // OK, which tree is it in? And is it quoted in the pattern?
825  if (is_unquoted_in_tree(hg, vh))
826  {
827  prtmsg("found bound variable in grounding tree:", vh);
828  prtmsg("matching pattern is:", hp);
829  prtmsg("proposed grounding is:", hg);
830 
831  if (is_quoted_in_tree(hp, vh)) continue;
832  dbgprt("miscompare; var is not in pattern, or its not quoted\n");
833  return false;
834  }
835  }
836  }
837 #endif
838 
839  // Let the callback perform basic checking.
840  bool match = _pmc.link_match(lp, lg);
841  if (not match) return false;
842 
843  dbgprt("depth=%d\n", depth);
844  prtmsg("> tree_compare", hp);
845  prtmsg("> to", hg);
846 
847  // CHOICE_LINK's are multiple-choice links. As long as we can
848  // can match one of the sub-expressions of the ChoiceLink, then
849  // the ChoiceLink as a whole can be considered to be grounded.
850  //
851  if (CHOICE_LINK == tp)
852  return choice_compare(ptm, hg, lp, lg);
853 
854  // If the two links are both ordered, its enough to compare
855  // them "side-by-side".
856  if (2 > lp->getArity() || _classserver.isA(tp, ORDERED_LINK))
857  return ordered_compare(ptm, hg, lp, lg);
858 
859  // If we are here, we are dealing with an unordered link.
860  return unorder_compare(ptm, hg, lp, lg);
861 }
862 
863 /* ======================================================== */
864 
865 /*
866  * The input pattern may contain many repeated sub-patterns. For example:
867  *
868  * ImplicationLink
869  * UnorderedLink
870  * VariableNode "$x"
871  * ConceptNode "this one"
872  * UnorderedLink
873  * VariableNode "$x"
874  * ConceptNode "this one"
875  *
876  * Suppose that we start searching the clause from VariableNode "$x" that
877  * occures twice in the pattern under UnorderedLink. While we traverse
878  * the pattern recursively we need to keep current state of permutations
879  * of UnorderedLink-s. We do not know which permutation will match. It may
880  * be different permutation for each occurence of UnorderedLink-s.
881  * This is the reason why we use PatternTerm pointers instead of atom Handles
882  * while traversing pattern tree. We need to keep permutation states for
883  * each term pointer separately.
884  *
885  * Next suppose our joining atom repeates in many sub-branches of a single
886  * ChoiceLink. For example:
887  *
888  * ChoiceLink
889  * UnorderedLink
890  * VariableNode "$x"
891  * ConceptNode "this one"
892  * UnorderedLink
893  * VariableNode "$x"
894  * ConceptNode "this one"
895  *
896  * We start pattern exploration for each occurence of joining atom. This is
897  * because of pruning being done in explore_choice_branches() when the first
898  * match is found. It seems that it may be refactored later. For now we iterate
899  * over all pattern terms associated with given atom handle.
900  *
901  */
903  const Handle& hg,
904  const Handle& clause_root)
905 {
906  try
907  {
908  // The term may appear in the clause in many places.
909  // Start exploration for each occurence
910  for (const PatternTermPtr &ptm :
911  _pat->connected_terms_map.at({term, clause_root}))
912  {
913  if (explore_link_branches(ptm, hg, clause_root))
914  return true;
915  }
916  } catch (const std::out_of_range&) {
917  dbgprt("Pattern term not found for %s, clause=%s\n",
918  hp->toShortString().c_str(),
919  clause_root->toShortString().c_str());
920  }
921  return false;
922 }
923 
948 bool PatternMatchEngine::explore_up_branches(const PatternTermPtr& ptm,
949  const Handle& hg,
950  const Handle& clause_root)
951 {
952  // Move up the solution graph, looking for a match.
953  IncomingSet iset = _pmc.get_incoming_set(hg);
954  size_t sz = iset.size();
955  dbgprt("Looking upward for term=%s have %zu branches\n",
956  ptm->toString().c_str(), sz);
957  bool found = false;
958  for (size_t i = 0; i < sz; i++) {
959  dbgprt("Try upward branch %zu of %zu for term=%s propose=%lu\n",
960  i, sz, ptm->toString().c_str(), Handle(iset[i]).value());
961  found = explore_link_branches(ptm, Handle(iset[i]), clause_root);
962  if (found) break;
963  }
964 
965  dbgprt("Found upward soln = %d\n", found);
966  return found;
967 }
968 
1002  const Handle& hg,
1003  const Handle& clause_root)
1004 {
1005  const Handle& hp = ptm->getHandle();
1006  // Let's not stare at our own navel. ... Unless the current
1007  // clause has GroundedPredicateNodes in it. In that case, we
1008  // have to make sure that they get evaluated.
1009  if ((hg == clause_root)
1010  and not is_evaluatable(clause_root))
1011  return false;
1012 
1013  // If its not an unordered link, then don't try to iterate.
1014  Type tp = hp->getType();
1015  if (not _classserver.isA(tp, UNORDERED_LINK))
1016  return explore_choice_branches(ptm, hg, clause_root);
1017 
1018  do {
1019  // If the pattern was satisfied, then we are done for good.
1020  if (explore_choice_branches(ptm, hg, clause_root))
1021  return true;
1022 
1023  dbgprt("Step to next permuation\n");
1024  // If we are here, there was no match.
1025  // On the next go-around, take a step.
1026  take_step = true;
1027  have_more = false;
1028  } while (have_perm(ptm, hg));
1029 
1030  dbgprt("No more unordered permutations\n");
1031 
1032  return false;
1033 }
1034 
1039  const Handle& hg,
1040  const Handle& clause_root)
1041 {
1042  const Handle& hp = ptm->getHandle();
1043  // If its not an choice link, then don't try to iterate.
1044  if (CHOICE_LINK != hp->getType())
1045  return explore_single_branch(ptm, hg, clause_root);
1046 
1047  dbgprt("Begin choice branchpoint iteration loop\n");
1048  do {
1049  // XXX this "need_choice_push thing is probably wrong; it probably
1050  // should resemble the perm_push() used for unordered links.
1051  // However, currently, no test case trips this up. so .. OK.
1052  // whatever. This still probably needs fixing.
1054  bool match = explore_single_branch(ptm, hg, clause_root);
1056  _need_choice_push = false;
1057 
1058  // If the pattern was satisfied, then we are done for good.
1059  if (match)
1060  return true;
1061 
1062  dbgprt("Step to next choice\n");
1063  // If we are here, there was no match.
1064  // On the next go-around, take a step.
1065  choose_next = true;
1066  } while (have_choice(ptm, hg));
1067 
1068  dbgprt("Exhausted all choice possibilities\n");
1069 
1070  return false;
1071 }
1072 
1090  const Handle& hg,
1091  const Handle& clause_root)
1092 {
1093  solution_push();
1094 
1095  dbgprt("Checking pattern term=%s for soln by %lu\n",
1096  ptm->toString().c_str(), hg.value());
1097 
1098  bool match = tree_compare(ptm, hg, CALL_SOLN);
1099 
1100  if (not match)
1101  {
1102  dbgprt("Pattern term=%s NOT solved by %lu\n",
1103  ptm->toString().c_str(), hg.value());
1104  solution_pop();
1105  return false;
1106  }
1107 
1108  dbgprt("Pattern term=%s solved by %lu move up\n",
1109  ptm->toString().c_str(), hg.value());
1110 
1111  // XXX should not do perm_push every time... only selectively.
1112  // But when? This is very confusing ...
1113  perm_push();
1114  bool found = do_term_up(ptm, hg, clause_root);
1115  perm_pop();
1116 
1117  solution_pop();
1118  return found;
1119 }
1120 
1161  const Handle& hg,
1162  const Handle& clause_root)
1163 {
1164  depth = 1;
1165 
1166  // If we are here, then everything below us matches. If we are
1167  // at the top of the clause, move on to the next clause. Else,
1168  // we are working on a term somewhere in the middle of a clause
1169  // and need to walk upwards.
1170  const Handle& hp = ptm->getHandle();
1171  if (hp == clause_root)
1172  return clause_accept(clause_root, hg);
1173 
1174  // Move upwards in the term, and hunt for a match, again.
1175  // There are two ways to move upwards: for a normal term, we just
1176  // find its parent in the clause. For an evaluatable term, we find
1177  // the parent evaluatable in the clause, which may be many steps
1178  // higher.
1179  dbgprt("Term = %s of clause UUID = %lu has ground, move upwards.\n",
1180  ptm->toString().c_str(), clause_root.value());
1181 
1182  if (0 < _pat->in_evaluatable.count(hp))
1183  {
1184  // If we are here, there are four possibilities:
1185  // 1) `hp` is not in any evaluatable that lies between it and
1186  // the clause root. In this case, we need to fall through
1187  // to the bottom.
1188  // 2) The evaluatable is the clause root. We evaluate it, and
1189  // consider the clause satisfied if the evaluation returns
1190  // true. In that case, we continue to the next clause, else we
1191  // backtrack.
1192  // 3) The evaluatable is in the middle of a clause, in which case,
1193  // it's parent must be a logical connective: an AndLink, an
1194  // OrLink or a NotLink. In this case, we have to loop over
1195  // all of the evaluatables within this clause, and connect
1196  // them as appropriate. The structure may be non-trivial, so
1197  // that presents a challange. However, it must be logical
1198  // connectives all the way up to the root of the clause, so the
1199  // easiest thing to do is simply to start at the top, and
1200  // recurse downwards. Ergo, this is much like case 2): the
1201  // evaluation either suceeds or fails; we proceed or backtrack.
1202  // 4) The evaluatable is in the middle of something else. We don't
1203  // know what that means, so we throw an error. Actually, this
1204  // is too harsh. It may be in the middle of some function that
1205  // expects a boolean value as an argument. But I don't know of
1206  // any, just right now.
1207  //
1208  // Anyway, all of this talk abbout booleans is emphasizing the
1209  // point that, someday, we need to replace this crisp logic with
1210  // probabalistic logic of some sort. XXX TODO. The fuzzy matcher
1211  // tries to do this, but I'm not sure its correct. We eventually
1212  // need to do this here, not there.
1213  //
1214  // By the way, if we are here, then `hp` is surely a variable;
1215  // or, at least, it is, if we are working in the canonical
1216  // interpretation.
1217 
1218  auto evra = _pat->in_evaluatable.equal_range(hp);
1219  for (auto evit = evra.first; evit != evra.second; evit++)
1220  {
1221  if (not is_unquoted_in_tree(clause_root, evit->second))
1222  continue;
1223 
1224  prtmsg("Term inside evaluatable, move up to it's top:\n",
1225  evit->second);
1226 
1227  // All of the variables occurring in the term should have
1228  // grounded by now. If not, then its virtual term, and we
1229  // shouldn't even be here (we can't just backtrack, and
1230  // try again later). So validate the grounding, but leave
1231  // the evaluation for the callback.
1232 // XXX TODO count the number of ungrounded vars !!! (make sure its zero)
1233 // XXX TODO make sure that all links from the clause_root to the term are
1234 // connectives (i.e. are in the _connectives set). Else throw an error.
1235 // why bother with this extra overhead, though?? Do we really need to do
1236 // this?
1237 
1238  bool found = _pmc.evaluate_sentence(clause_root, var_grounding);
1239  dbgprt("After evaluating clause, found = %d\n", found);
1240  if (found)
1241  return clause_accept(clause_root, hg);
1242 
1243  return false;
1244  }
1245  }
1246 
1247  PatternTermPtr parent = ptm->getParent();
1248  OC_ASSERT(PatternTerm::UNDEFINED != parent, "Unknown term parent");
1249 
1250  const Handle& hi = parent->getHandle();
1251 
1252  // Do the simple case first, ChoiceLinks are harder.
1253  bool found = false;
1254  if (CHOICE_LINK != hi->getType())
1255  {
1256  if (explore_up_branches(parent, hg, clause_root)) found = true;
1257  dbgprt("After moving up the clause, found = %d\n", found);
1258  }
1259  else
1260  if (hi == clause_root)
1261  {
1262  dbgprt("Exploring ChoiceLink at root\n");
1263  if (clause_accept(clause_root, hg)) found = true;
1264  }
1265  else
1266  {
1267  // If we are here, we have an embedded ChoiceLink, i.e. a
1268  // ChoiceLink that is not at the clause root. It's contained
1269  // in some other link, and we have to get that link and
1270  // perform comparisons on it. i.e. we have to "hop over"
1271  // (hop up) past the ChoiceLink, before resuming the search.
1272  // The easiest way to hop is to do it recursively... i.e.
1273  // call ourselves again.
1274  dbgprt("Exploring ChoiceLink below root\n");
1275 
1276  OC_ASSERT(not have_choice(parent, hg),
1277  "Something is wrong with the ChoiceLink code");
1278 
1279  _need_choice_push = true;
1280  if (do_term_up(parent, hg, clause_root)) found = true;
1281  }
1282 
1283  return found;
1284 }
1285 
1292  const Handle& hg)
1293 {
1294  // Is this clause a required clause? If so, then let the callback
1295  // make the final decision; if callback rejects, then it's the
1296  // same as a mismatch; try the next one.
1297  bool match;
1298  if (is_optional(clause_root))
1299  {
1300  clause_accepted = true;
1301  match = _pmc.optional_clause_match(clause_root, hg);
1302  dbgprt("optional clause match callback match=%d\n", match);
1303  }
1304  else
1305  {
1306  match = _pmc.clause_match(clause_root, hg);
1307  dbgprt("clause match callback match=%d\n", match);
1308  }
1309  if (not match) return false;
1310 
1311  clause_grounding[clause_root] = hg;
1312  prtmsg("---------------------\nclause:", clause_root);
1313  prtmsg("ground:", hg);
1314 
1315  // Now go and do more clauses.
1316  return do_next_clause();
1317 }
1318 
1319 // This is called when all previous clauses have been grounded; so
1320 // we search for the next one, and try to round that.
1322 {
1325  Handle joiner = next_joint;
1326  Handle curr_root = next_clause;
1327 
1328  // If there are no further clauses to solve,
1329  // we are really done! Report the solution via callback.
1330  bool found = false;
1331  if (Handle::UNDEFINED == curr_root)
1332  {
1333 #ifdef DEBUG
1334  dbgprt ("==================== FINITO!\n");
1336 #endif
1338  }
1339  else
1340  {
1341  prtmsg("Next clause is\n", curr_root);
1342  dbgprt("This clause is %s\n",
1343  is_optional(curr_root)? "optional" : "required");
1344  dbgprt("This clause is %s\n",
1345  is_evaluatable(curr_root)?
1346  "dynamically evaluatable" : "non-dynamic");
1347  prtmsg("Joining variable is", joiner);
1348  prtmsg("Joining grounding is", var_grounding[joiner]);
1349 
1350  // Else, start solving the next unsolved clause. Note: this is
1351  // a recursive call, and not a loop. Recursion is halted when
1352  // the next unsolved clause has no grounding.
1353  //
1354  // We continue our search at the atom that "joins" (is shared
1355  // in common) between the previous (solved) clause, and this
1356  // clause. If the "join" was a variable, look up its grounding;
1357  // else the join is a 'real' atom.
1358 
1359  clause_accepted = false;
1360  Handle hgnd = var_grounding[joiner];
1361  OC_ASSERT(hgnd != Handle::UNDEFINED,
1362  "Error: joining handle has not been grounded yet!");
1363  found = explore_clause(joiner, hgnd, curr_root);
1364 
1365  // If we are here, and found is false, then we've exhausted all
1366  // of the search possibilities for the current clause. If this
1367  // is an optional clause, and no solutions were reported for it,
1368  // then report the failure of finding a solution now. If this was
1369  // also the final optional clause, then in fact, we've got a
1370  // grounding for the whole thing ... report that!
1371  //
1372  // Note that lack of a match halts recursion; thus, we can't
1373  // depend on recursion to find additional unmatched optional
1374  // clauses; thus we have to explicitly loop over all optional
1375  // clauses that don't have matches.
1376  while ((false == found) and
1377  (false == clause_accepted) and
1378  (is_optional(curr_root)))
1379  {
1380  Handle undef(Handle::UNDEFINED);
1381  bool match = _pmc.optional_clause_match(joiner, undef);
1382  dbgprt ("Exhausted search for optional clause, cb=%d\n", match);
1383  if (not match) {
1385  return false;
1386  }
1387 
1388  // XXX Maybe should push n pop here? No, maybe not ...
1389  clause_grounding[curr_root] = Handle::UNDEFINED;
1391  joiner = next_joint;
1392  curr_root = next_clause;
1393 
1394  prtmsg("Next optional clause is", curr_root);
1395  if (Handle::UNDEFINED == curr_root)
1396  {
1397  dbgprt ("==================== FINITO BANDITO!\n");
1398 #ifdef DEBUG
1400 #endif
1402  }
1403  else
1404  {
1405  // Now see if this optional clause has any solutions,
1406  // or not. If it does, we'll recurse. If it does not,
1407  // we'll loop around back to here again.
1408  clause_accepted = false;
1409  Handle hgnd = var_grounding[joiner];
1410  found = explore_term_branches(joiner, hgnd, curr_root);
1411  }
1412  }
1413  }
1414 
1415  // If we failed to find anything at this level, we need to
1416  // backtrack, i.e. pop the stack, and begin a search for
1417  // other possible matches and groundings.
1419 
1420  return found;
1421 }
1422 
1455 {
1456  // First, try to ground all the mandatory clauses, only.
1457  // no virtuals, no black boxes, no optionals.
1458  if (get_next_thinnest_clause(false, false, false)) return;
1459 
1460  // Don't bother looking for evaluatables if they are not there.
1461  if (not _pat->evaluatable_holders.empty())
1462  {
1463  if (get_next_thinnest_clause(true, false, false)) return;
1464  if (not _pat->black.empty())
1465  {
1466  if (get_next_thinnest_clause(true, true, false)) return;
1467  }
1468  }
1469 
1470  // If there are no optional clauses, we are done.
1471  if (_pat->optionals.empty())
1472  {
1473  // There are no more ungrounded clauses to consider. We are done.
1476  return;
1477  }
1478 
1479  // Try again, this time, considering the optional clauses.
1480  if (get_next_thinnest_clause(false, false, true)) return;
1481  if (not _pat->evaluatable_holders.empty())
1482  {
1483  if (get_next_thinnest_clause(true, false, true)) return;
1484  if (not _pat->black.empty())
1485  {
1486  if (get_next_thinnest_clause(true, true, true)) return;
1487  }
1488  }
1489 
1490  // If we are here, there are no more unsolved clauses to consider.
1493 }
1494 
1495 // Count the number of ungrounded variables in a clause.
1496 //
1497 // This is used to search for the "thinnest" ungrounded clause:
1498 // the one with the fewest ungrounded variables in it. Thus, if
1499 // there is just one variable that needs to be grounded, then this
1500 // can be done in a direct fashion; it resembles the concept of
1501 // "unit propagation" in the DPLL algorithm.
1502 //
1503 // XXX TODO ... Rather than counting the number of variables, we
1504 // should instead look for one with the smallest incoming set.
1505 // That is because the very next thing that we do will be to
1506 // iterate over the incoming set of "pursue" ... so it could be
1507 // a huge pay-off to minimize this.
1508 //
1509 // If there are two ungrounded variables in a clause, then the
1510 // "thickness" is the *product* of the sizes of the two incoming
1511 // sets. Thus, the fewer ungrounded variables, the better.
1512 //
1513 // Danger: this assumes a suitable dataset, as otherwise, the cost
1514 // of this "optimization" can add un-necessarily to the overhead.
1515 //
1516 unsigned int PatternMatchEngine::thickness(const Handle& clause,
1517  const std::set<Handle>& live)
1518 {
1519  // If there are only zero or one ungrounded vars, then any clause
1520  // will do. Blow this pop stand.
1521  if (live.size() < 2) return 1;
1522 
1523  unsigned int count = 0;
1524  for (const Handle& v : live)
1525  {
1526  if (is_unquoted_in_tree(clause, v)) count++;
1527  }
1528  return count;
1529 }
1530 
1537  bool search_black,
1538  bool search_optionals)
1539 {
1540  // Search for an as-yet ungrounded clause. Search for required
1541  // clauses first; then, only if none of those are left, move on
1542  // to the optional clauses. We can find ungrounded clauses by
1543  // looking at the grounded vars, looking up the root, to see if
1544  // the root is grounded. If its not, start working on that.
1545  Handle joint(Handle::UNDEFINED);
1546  Handle unsolved_clause(Handle::UNDEFINED);
1547  unsigned int thinnest_joint = UINT_MAX;
1548  unsigned int thinnest_clause = UINT_MAX;
1549  bool unsolved = false;
1550 
1551  // Make a list of the as-yet ungrounded variables.
1552  std::set<Handle> ungrounded_vars;
1553 
1554  // Grounded variables ordered by the size of their grounding incoming set
1555  std::multimap<std::size_t, Handle> thick_vars;
1556 
1557  for (const Handle &v : _varlist->varset)
1558  {
1559  try {
1560  const Handle& gnd = var_grounding.at(v);
1561  if (Handle::UNDEFINED != gnd)
1562  {
1563  std::size_t incoming_set_size = gnd->getIncomingSetSize();
1564  thick_vars.insert(std::make_pair(incoming_set_size, v));
1565  }
1566  else ungrounded_vars.insert(v);
1567  }
1568  catch(...) { ungrounded_vars.insert(v); }
1569  }
1570 
1571  // We are looking for a joining atom, one that is shared in common
1572  // with the a fully grounded clause, and an as-yet ungrounded clause.
1573  // The joint is called "pursue", and the unsolved clause that it
1574  // joins will become our next untried clause. We choose joining atom
1575  // with smallest size of its incoming set. If there are many such
1576  // atoms we choose one from clauses with minimal number of ungrounded
1577  // yet variables.
1578  for (auto tckvar : thick_vars)
1579  {
1580  std::size_t pursue_thickness = tckvar.first;
1581  const Handle& pursue = tckvar.second;
1582 
1583  if (pursue_thickness > thinnest_joint) break;
1584 
1585  try { _pat->connectivity_map.at(pursue); }
1586  catch(...) { continue; }
1587  const Pattern::RootList& rl(_pat->connectivity_map.at(pursue));
1588 
1589  for (const Handle& root : rl)
1590  {
1591  if ((issued.end() == issued.find(root))
1592  and (search_virtual or not is_evaluatable(root))
1593  and (search_black or not is_black(root))
1594  and (search_optionals or not is_optional(root)))
1595  {
1596  unsigned int root_thickness = thickness(root, ungrounded_vars);
1597  if (root_thickness < thinnest_clause)
1598  {
1599  thinnest_clause = root_thickness;
1600  thinnest_joint = pursue_thickness;
1601  unsolved_clause = root;
1602  joint = pursue;
1603  unsolved = true;
1604  }
1605  }
1606  }
1607  }
1608 
1609  if (unsolved)
1610  {
1611  // Joint is a (variable) node that's shared between several
1612  // clauses. One of the clauses has been grounded, another
1613  // has not. We want to now traverse upwards from this node,
1614  // to find the top of the ungrounded clause.
1615  next_clause = unsolved_clause;
1616  next_joint = joint;
1617 
1618  if (Handle::UNDEFINED != unsolved_clause)
1619  {
1620  issued.insert(unsolved_clause);
1621  return true;
1622  }
1623  }
1624 
1625  return false;
1626 }
1627 
1628 /* ======================================================== */
1644 {
1646  dbgprt("--- That's it, now push to stack depth=%d\n\n", _clause_stack_depth);
1647 
1648  OC_ASSERT(not in_quote, "Can't posssibly happen!");
1649 
1652 
1653  issued_stack.push(issued);
1655 
1656  perm_push();
1657 
1658  _pmc.push();
1659 }
1660 
1668 {
1669  _pmc.pop();
1670 
1671  // The grounding stacks are handled differently.
1675 
1677 
1678  perm_pop();
1679 
1681 
1682  dbgprt("pop to depth %d\n", _clause_stack_depth);
1683 }
1684 
1693 {
1694  _clause_stack_depth = 0;
1695 #if 0
1696  OC_ASSERT(0 == term_solutn_stack.size());
1697  OC_ASSERT(0 == var_solutn_stack.size());
1698  OC_ASSERT(0 == issued_stack.size());
1699  OC_ASSERT(0 == choice_stack.size());
1700  OC_ASSERT(0 == perm_stack.size());
1701 #else
1702  while (!term_solutn_stack.empty()) term_solutn_stack.pop();
1703  while (!var_solutn_stack.empty()) var_solutn_stack.pop();
1704  while (!issued_stack.empty()) issued_stack.pop();
1705  while (!choice_stack.empty()) choice_stack.pop();
1706  while (!perm_stack.empty()) perm_stack.pop();
1707 #endif
1708 }
1709 
1711 {
1714 }
1715 
1717 {
1720 }
1721 
1723 {
1724  var_solutn_stack.pop();
1725  term_solutn_stack.pop();
1726 }
1727 
1728 /* ======================================================== */
1729 
1756  const Handle& term,
1757  const Handle& grnd)
1758 {
1760  return explore_redex(term, grnd, do_clause);
1761 }
1762 
1768  const Handle& grnd,
1769  const Handle& first_clause)
1770 {
1771  if (term == Handle::UNDEFINED)
1772  return false;
1773 
1774  // Cleanup
1776 
1777  // Match the required clauses.
1778  issued.insert(first_clause);
1779  return explore_clause(term, grnd, first_clause);
1780 }
1781 
1794  const Handle& grnd,
1795  const Handle& clause)
1796 {
1797  // If we are looking for a pattern to match, then ... look for it.
1798  // Evaluatable clauses are not patterns; they are clauses that
1799  // evaluate to true or false.
1800  if (not is_evaluatable(clause))
1801  {
1802  dbgprt("Clause is matchable; start matching it.\n");
1803  bool found = explore_term_branches(term, grnd, clause);
1804 
1805  // If found is false, then there's no solution here.
1806  // Bail out, return false to try again with the next candidate.
1807  return found;
1808  }
1809 
1810  // If we are here, we have an evaluatable clause on our hands.
1811  dbgprt("Clause is evaluatable; start evaluating it\n");
1812  bool found = _pmc.evaluate_sentence(clause, var_grounding);
1813  dbgprt("Post evaluating clause, found = %d\n", found);
1814  if (found)
1815  return clause_accept(clause, grnd);
1816 
1817  return false;
1818 }
1819 
1825 {
1826  // Clear all state.
1827  var_grounding.clear();
1828  clause_grounding.clear();
1829  in_quote = false;
1830 
1831  depth = 0;
1832 
1833  // choice link state
1834  _choice_state.clear();
1835  _need_choice_push = false;
1836  choose_next = true;
1837 
1838  // unordered link state
1839  have_more = false;
1840  take_step = true;
1841  _perm_state.clear();
1842 
1843  issued.clear();
1844 }
1845 
1847  const Variables& v,
1848  const Pattern& p)
1849  : _pmc(pmcb),
1850  _classserver(classserver()),
1851  _varlist(&v),
1852  _pat(&p)
1853 {
1854  // current state
1855  in_quote = false;
1856  depth = 0;
1857 
1858  // graph state
1859  _clause_stack_depth = 0;
1860 
1861  // choice link state
1862  _need_choice_push = false;
1863  choose_next = true;
1864 
1865  // unordered link state
1866  have_more = false;
1867  take_step = true;
1868 }
1869 
1870 /* ======================================================== */
1871 
1873  const std::map<Handle, Handle> &vars,
1874  const std::map<Handle, Handle> &clauses)
1875 {
1876  printf("\nVariable groundings:\n");
1877 
1878  // Print out the bindings of solutions to variables.
1879  std::map<Handle, Handle>::const_iterator j = vars.begin();
1880  std::map<Handle, Handle>::const_iterator jend = vars.end();
1881  for (; j != jend; ++j)
1882  {
1883  Handle var(j->first);
1884  Handle soln(j->second);
1885 
1886  // Only print grounding for variables.
1887  if (VARIABLE_NODE != var->getType()) continue;
1888 
1889  if (soln == Handle::UNDEFINED)
1890  {
1891  printf("ERROR: ungrounded variable %s\n",
1892  var->toShortString().c_str());
1893  continue;
1894  }
1895 
1896  printf("\t%s maps to %s\n",
1897  var->toShortString().c_str(),
1898  soln->toShortString().c_str());
1899  }
1900 
1901  // Print out the full binding to all of the clauses.
1902  printf("\nGrounded clauses:\n");
1903  std::map<Handle, Handle>::const_iterator m;
1904  int i = 0;
1905  for (m = clauses.begin(); m != clauses.end(); ++m, ++i)
1906  {
1907  if (m->second == Handle::UNDEFINED)
1908  {
1909  Handle mf(m->first);
1910  prtmsg("ERROR: ungrounded clause: ", mf);
1911  continue;
1912  }
1913  std::string str = m->second->toShortString();
1914  printf ("%d. %s\n", i, str.c_str());
1915  }
1916  printf ("\n");
1917 }
1918 
1923  const std::set<Handle> &vars,
1924  const std::vector<Handle> &clauses)
1925 {
1926  printf("\nClauses:\n");
1927  for (Handle h : clauses) prt(h);
1928 
1929  printf("\nVars:\n");
1930  for (Handle h : vars) prt(h);
1931 }
1932 
1933 /* ===================== END OF FILE ===================== */
virtual bool optional_clause_match(const Handle &pattrn, const Handle &grnd)=0
virtual bool evaluate_sentence(const Handle &eval, const std::map< Handle, Handle > &gnds)=0
static bool prt(const Handle &h)
bool explore_neighborhood(const Handle &, const Handle &, const Handle &)
std::stack< SolnMap > var_solutn_stack
PatternMatchEngine(PatternMatchCallback &, const Variables &, const Pattern &)
std::shared_ptr< PatternTerm > PatternTermPtr
Definition: PatternTerm.h:35
std::vector< Handle > HandleSeq
a list of handles
Definition: Handle.h:246
std::set< Handle > evaluatable_holders
Definition: Pattern.h:121
std::set< Handle > varset
Definition: Pattern.h:65
static void print_solution(const std::map< Handle, Handle > &vars, const std::map< Handle, Handle > &clauses)
bool do_term_up(const PatternTermPtr &, const Handle &, const Handle &)
std::map< Handle, Handle > var_grounding
#define POPSTK(stack, soln)
virtual std::string toShortString(std::string indent="")=0
static bool is_quoted_in_tree(const Handle &tree, const Handle &atom)
Definition: FindUtils.h:205
Handle getHandle()
Definition: Atom.h:211
std::map< Handle, Handle > clause_grounding
virtual bool post_link_match(const LinkPtr &patt_link, const LinkPtr &grnd_link)
bool have_choice(const PatternTermPtr &, const Handle &)
Type getType() const
Definition: Atom.h:197
static bool any_unquoted_in_tree(const Handle &tree, const std::set< Handle > &atoms)
Definition: FindUtils.h:269
std::shared_ptr< Link > LinkPtr
Definition: Atom.h:53
std::pair< PatternTermPtr, Handle > Choice
ClassServer & classserver(ClassServerFactory *=ClassServer::createInstance)
Definition: ClassServer.cc:159
virtual IncomingSet get_incoming_set(const Handle &h)
static NodePtr NodeCast(const Handle &h)
Definition: Node.h:113
std::vector< PatternTermPtr > PatternTermSeq
Definition: PatternTerm.h:37
bool get_next_thinnest_clause(bool, bool, bool)
bool self_compare(const Handle &)
bool explore_link_branches(const PatternTermPtr &, const Handle &, const Handle &)
static const Handle UNDEFINED
Definition: Handle.h:77
#define dbgprt(f, varargs...)
std::stack< SolnMap > term_solutn_stack
bool explore_choice_branches(const PatternTermPtr &, const Handle &, const Handle &)
bool quote_compare(const PatternTermPtr &, const Handle &)
unsigned int thickness(const Handle &, const std::set< Handle > &)
bool is_black(const Handle &h)
virtual bool clause_match(const Handle &pattrn_link_h, const Handle &grnd_link_h)
virtual bool variable_match(const Handle &patt_node, const Handle &grnd_node)=0
std::pair< PatternTermPtr, Handle > Unorder
PatternMatchCallback & _pmc
bool isA(Type sub, Type super)
Definition: ClassServer.h:144
virtual bool link_match(const LinkPtr &patt_link, const LinkPtr &grnd_link)=0
bool explore_single_branch(const PatternTermPtr &, const Handle &, const Handle &)
bool variable_compare(const Handle &, const Handle &)
bool explore_redex(const Handle &, const Handle &, const Handle &)
virtual bool node_match(const Handle &patt_node, const Handle &grnd_node)=0
std::unordered_multimap< Handle, Handle > in_evaluatable
Definition: Pattern.h:131
static LinkPtr LinkCast(const Handle &h)
Definition: Link.h:263
std::stack< IssuedSet > issued_stack
bool unorder_compare(const PatternTermPtr &, const Handle &, const LinkPtr &, const LinkPtr &)
std::vector< LinkPtr > IncomingSet
Definition: Atom.h:55
static const PatternTermPtr UNDEFINED
Definition: PatternTerm.h:47
virtual bool grounding(const std::map< Handle, Handle > &var_soln, const std::map< Handle, Handle > &term_soln)=0
std::shared_ptr< Node > NodePtr
Definition: Node.h:112
ConnectMap connectivity_map
Definition: Pattern.h:139
UUID value(void) const
Definition: Handle.h:85
bool is_optional(const Handle &h)
std::set< Handle > black
Definition: Pattern.h:116
std::stack< ChoiceState > choice_stack
unsigned short Type
type of Atoms, represented as short integer (16 bits)
Definition: types.h:40
static void print_term(const std::set< Handle > &vars, const std::vector< Handle > &clauses)
std::set< Handle > optionals
Definition: Pattern.h:110
size_t getIncomingSetSize()
Get the size of the incoming set.
Definition: Atom.cc:310
bool explore_clause(const Handle &, const Handle &, const Handle &)
bool ordered_compare(const PatternTermPtr &, const Handle &, const LinkPtr &, const LinkPtr &)
size_t curr_choice(const PatternTermPtr &, const Handle &, bool &)
bool explore_term_branches(const Handle &, const Handle &, const Handle &)
bool clause_accept(const Handle &, const Handle &)
Permutation curr_perm(const PatternTermPtr &, const Handle &, bool &)
bool explore_up_branches(const PatternTermPtr &, const Handle &, const Handle &)
bool is_evaluatable(const Handle &h)
bool tree_compare(const PatternTermPtr &, const Handle &, Caller)
static void prtmsg(const char *msg, const Handle &h)
bool choice_compare(const PatternTermPtr &, const Handle &, const LinkPtr &, const LinkPtr &)
bool have_perm(const PatternTermPtr &, const Handle &)
ConnectTermMap connected_terms_map
Definition: Pattern.h:141
bool node_compare(const Handle &, const Handle &)
Compare two nodes, one in the pattern, one proposed grounding.
virtual bool fuzzy_match(const Handle &ph, const Handle &gh)
std::vector< Handle > RootList
Definition: Pattern.h:79
std::stack< PermState > perm_stack
static bool is_unquoted_in_tree(const Handle &tree, const Handle &atom)
Definition: FindUtils.h:232