From b27ec7843de0e5eb5b240262eeb358aec622ec1c Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 00:49:13 -0600 Subject: [PATCH 01/21] Change inheritance of ImplicatinScope to be RuleLink --- opencog/atoms/atom_types/atom_types.script | 7 ++++--- opencog/atoms/core/FilterLink.cc | 8 ++++---- tests/atoms/execution/filter-link.scm | 12 ++++++------ 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/opencog/atoms/atom_types/atom_types.script b/opencog/atoms/atom_types/atom_types.script index c6c94ca914..fdaeb830cc 100644 --- a/opencog/atoms/atom_types/atom_types.script +++ b/opencog/atoms/atom_types/atom_types.script @@ -1110,9 +1110,10 @@ DIRECTLY_EVALUATABLE_LINK <- LINK // for more information IMPLICATION_LINK <- ORDERED_LINK, DIRECTLY_EVALUATABLE_LINK -// ImplicationScopeLink should be moved to PLN at earliest -// convenience. XXX FIXME. -IMPLICATION_SCOPE_LINK <- SCOPE_LINK +// ImplicationScopeLink is a synonym for RuleLink, as far as I can tell. +// It is used by PLN to do more or less the same thig as RuleLink. +// At any rate, it should be moved there. XXX FIXME. +IMPLICATION_SCOPE_LINK <- RULE_LINK INHERITANCE_LINK <- ORDERED_LINK, DIRECTLY_EVALUATABLE_LINK diff --git a/opencog/atoms/core/FilterLink.cc b/opencog/atoms/core/FilterLink.cc index 5f7731fb38..39f7a39311 100644 --- a/opencog/atoms/core/FilterLink.cc +++ b/opencog/atoms/core/FilterLink.cc @@ -55,17 +55,17 @@ void FilterLink::init(void) _mvars = &_pattern->get_variables(); _varset = &_mvars->varset; - // ImplicationScopeLinks are a special type of ScopeLink. They specify - // a re-write that should be performed. Viz, ImplicationScopeLinks are + // RuleLinks are a special type of ScopeLink. They specify a + // re-write that should be performed. Viz, RuleLinks are // of the form P(x)->Q(x). Here, the `_rewrite` is the Q(x) _is_impl = false; - if (nameserver().isA(tscope, IMPLICATION_SCOPE_LINK)) + if (nameserver().isA(tscope, RULE_LINK)) { _is_impl = true; const HandleSeq& impl = _pattern->getOutgoingSet(); if (impl.size() < 2) throw SyntaxException(TRACE_INFO, - "Expecting ImplicationLink of at least size 2."); + "Expecting a RuleLink of at least size 2."); // ImplicationScopeLinks have arity 2 only if they have no type // constraints, else they have arity 3. That is, an diff --git a/tests/atoms/execution/filter-link.scm b/tests/atoms/execution/filter-link.scm index 4cbfa114ce..d071d49b5e 100644 --- a/tests/atoms/execution/filter-link.scm +++ b/tests/atoms/execution/filter-link.scm @@ -214,11 +214,11 @@ ) ;; ------------------------------------------------------------- -;; ImplicationScopeLink tests. +;; RuleLink tests. (define imply-map (FilterLink - (ImplicationScopeLink + (RuleLink (VariableList (TypedVariable (Variable "$x") (Type "ConceptNode")) (TypedVariable (Variable "$y") (Type "ConceptNode"))) @@ -254,7 +254,7 @@ (define imply-eval (FilterLink - (ImplicationScopeLink + (RuleLink (VariableList (TypedVariable (Variable "$x") (Type "ConceptNode")) (TypedVariable (Variable "$y") (Type "NumberNode"))) @@ -286,11 +286,11 @@ ) ;; ------------------------------------------------------------- -;; Implicit-variable ImplicationScopeLink tests. +;; Implicit-variable RuleLink tests. (define imply-map-nodecl (FilterLink - (ImplicationScopeLink + (RuleLink (EvaluationLink (Predicate "foo") (ListLink (Variable "$x") (Variable "$y"))) @@ -314,7 +314,7 @@ (define imply-glob-nodecl (FilterLink - (ImplicationScopeLink + (RuleLink (EvaluationLink (Predicate "goo") (ListLink (Concept "bar") (Glob "$y"))) From 2a55ac6e011798f9d4ed9532a81b9904720e5b3f Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 00:58:17 -0600 Subject: [PATCH 02/21] Revert parts that make URE BackwardChainerUTest fail. URE Hangs, because RuleLink::execute() does something it doesn't expect. Don't know what the problem actually is. --- opencog/atoms/atom_types/atom_types.script | 4 +++- opencog/atoms/core/FilterLink.cc | 9 ++++++++- opencog/atoms/core/TypedVariableLink.cc | 3 ++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/opencog/atoms/atom_types/atom_types.script b/opencog/atoms/atom_types/atom_types.script index fdaeb830cc..2d7e189145 100644 --- a/opencog/atoms/atom_types/atom_types.script +++ b/opencog/atoms/atom_types/atom_types.script @@ -1112,8 +1112,10 @@ IMPLICATION_LINK <- ORDERED_LINK, DIRECTLY_EVALUATABLE_LINK // ImplicationScopeLink is a synonym for RuleLink, as far as I can tell. // It is used by PLN to do more or less the same thig as RuleLink. +// Oh, but BackwardChainerUTest hangs when it inherits from RuleLink... // At any rate, it should be moved there. XXX FIXME. -IMPLICATION_SCOPE_LINK <- RULE_LINK +// IMPLICATION_SCOPE_LINK <- RULE_LINK +IMPLICATION_SCOPE_LINK <- SCOPE_LINK INHERITANCE_LINK <- ORDERED_LINK, DIRECTLY_EVALUATABLE_LINK diff --git a/opencog/atoms/core/FilterLink.cc b/opencog/atoms/core/FilterLink.cc index 39f7a39311..207c83bc9d 100644 --- a/opencog/atoms/core/FilterLink.cc +++ b/opencog/atoms/core/FilterLink.cc @@ -21,8 +21,9 @@ #include #include -#include #include +#include +#include #include "FilterLink.h" @@ -60,6 +61,12 @@ void FilterLink::init(void) // of the form P(x)->Q(x). Here, the `_rewrite` is the Q(x) _is_impl = false; if (nameserver().isA(tscope, RULE_LINK)) + { + _is_impl = true; + _rewrite = RuleLinkCast(_pattern)->get_implicand()[0]; + } + + if (nameserver().isA(tscope, IMPLICATION_SCOPE_LINK)) { _is_impl = true; const HandleSeq& impl = _pattern->getOutgoingSet(); diff --git a/opencog/atoms/core/TypedVariableLink.cc b/opencog/atoms/core/TypedVariableLink.cc index ab4fde5b6c..78d195dd0e 100644 --- a/opencog/atoms/core/TypedVariableLink.cc +++ b/opencog/atoms/core/TypedVariableLink.cc @@ -43,7 +43,8 @@ void TypedVariableLink::init() if (VARIABLE_NODE != stype and GLOB_NODE != stype) throw SyntaxException(TRACE_INFO, - "Sorry, we expect type names to be variables!"); + "Sorry, we expect type names to be variables! Got=%s", + to_short_string().c_str()); // Allow VARIABLE_NODE, although this is a bug in the URE, // which should be using a SignatureLink for this case. XXX FIXME. From b357b30903c0268dc67dbb551866acf54a388c12 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 11:32:21 -0600 Subject: [PATCH 03/21] Commentary --- opencog/atoms/atom_types/atom_types.script | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/opencog/atoms/atom_types/atom_types.script b/opencog/atoms/atom_types/atom_types.script index 2d7e189145..81165616c9 100644 --- a/opencog/atoms/atom_types/atom_types.script +++ b/opencog/atoms/atom_types/atom_types.script @@ -1111,9 +1111,10 @@ DIRECTLY_EVALUATABLE_LINK <- LINK IMPLICATION_LINK <- ORDERED_LINK, DIRECTLY_EVALUATABLE_LINK // ImplicationScopeLink is a synonym for RuleLink, as far as I can tell. -// It is used by PLN to do more or less the same thig as RuleLink. -// Oh, but BackwardChainerUTest hangs when it inherits from RuleLink... -// At any rate, it should be moved there. XXX FIXME. +// It is used by PLN to do more or less the same thing as RuleLink. +// Except that BackwardChainerUTest hangs when it inherits from +// RuleLink, because RuleLink::execute() does something that URE isn't +// expecting. At any rate, it should be moved there. XXX FIXME. // IMPLICATION_SCOPE_LINK <- RULE_LINK IMPLICATION_SCOPE_LINK <- SCOPE_LINK From 4858821c0d026f7c6a19d11d8ccc659022040427 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 12:10:06 -0600 Subject: [PATCH 04/21] Allow multiple-target rewrite links --- opencog/atoms/core/FilterLink.cc | 40 ++++++++++++++++++-------------- opencog/atoms/core/FilterLink.h | 4 ++-- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/opencog/atoms/core/FilterLink.cc b/opencog/atoms/core/FilterLink.cc index 207c83bc9d..3808142981 100644 --- a/opencog/atoms/core/FilterLink.cc +++ b/opencog/atoms/core/FilterLink.cc @@ -59,16 +59,14 @@ void FilterLink::init(void) // RuleLinks are a special type of ScopeLink. They specify a // re-write that should be performed. Viz, RuleLinks are // of the form P(x)->Q(x). Here, the `_rewrite` is the Q(x) - _is_impl = false; if (nameserver().isA(tscope, RULE_LINK)) - { - _is_impl = true; - _rewrite = RuleLinkCast(_pattern)->get_implicand()[0]; - } + _rewrite = RuleLinkCast(_pattern)->get_implicand(); + // The URE ControlPolicyUTest makes use of this, and we cannot + // yet use RuleLink, above, to handle this, because then + // the URE BackwardChainerUTest hangs. Argh... if (nameserver().isA(tscope, IMPLICATION_SCOPE_LINK)) { - _is_impl = true; const HandleSeq& impl = _pattern->getOutgoingSet(); if (impl.size() < 2) throw SyntaxException(TRACE_INFO, @@ -80,14 +78,14 @@ void FilterLink::init(void) // where T(x) is the type constraints on the variables. if (_pattern->get_body() == impl[0]) { - _rewrite = impl[1]; + _rewrite.push_back(impl[1]); } else if (_pattern->get_body() == impl[1]) { if (impl.size() < 3) throw SyntaxException(TRACE_INFO, "Expecting ImplicationScopeLink of at least size 3."); - _rewrite = impl[2]; + _rewrite.push_back(impl[2]); } } @@ -341,21 +339,27 @@ Handle FilterLink::rewrite_one(const Handle& cterm, AtomSpace* scratch) const valseq.emplace_back(valpair->second); } - // Perform substitution, if it's an ImplicationScopeLink - if (_is_impl) + // Make sure each variable is grounded. (for real, this time) + if (partial) + return Handle::UNDEFINED; + + // Perform substitution, if it's a RuleLink. + if (not _rewrite.empty()) { + HandleSeq rew; // Beta reduce, and execute. No type-checking during // beta-reduction; we've already done that. - Handle red(_mvars->substitute_nocheck(_rewrite, valseq)); - return HandleCast(inst.execute(red)); - } + for (const Handle& impl : _rewrite) + { + Handle red(_mvars->substitute_nocheck(impl, valseq)); + rew.emplace_back(HandleCast(inst.execute(red))); + } - // Make sure each variable is grounded. (for real, this time) - if (partial) - return Handle::UNDEFINED; + valseq.swap(rew); + } - // Wrap up the result in a list only if there is more than one - // variable. + // Wrap up the result in a ListLink only if there is more + // than one variable. size_t nv = valseq.size(); if (1 < nv) return scratch->add_link(LIST_LINK, std::move(valseq)); diff --git a/opencog/atoms/core/FilterLink.h b/opencog/atoms/core/FilterLink.h index 021ca72ef5..036699fc2e 100644 --- a/opencog/atoms/core/FilterLink.h +++ b/opencog/atoms/core/FilterLink.h @@ -50,8 +50,8 @@ class FilterLink : public FunctionLink // Globby terms are terms that contain a GlobNode HandleSet _globby_terms; // Smallest term that has a glob. - bool _is_impl; - Handle _rewrite; + // Rules will have a rewrite + HandleSeq _rewrite; void init(void); From 4f0fc2174c603e6f15e92272b8a11f106dff5160 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 12:46:21 -0600 Subject: [PATCH 05/21] Rewrite some confusing documentation. --- opencog/atoms/core/FilterLink.cc | 6 +++--- opencog/atoms/core/FreeVariables.cc | 2 +- opencog/atoms/core/FreeVariables.h | 18 ++++++++---------- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/opencog/atoms/core/FilterLink.cc b/opencog/atoms/core/FilterLink.cc index 3808142981..5f174df673 100644 --- a/opencog/atoms/core/FilterLink.cc +++ b/opencog/atoms/core/FilterLink.cc @@ -31,9 +31,9 @@ using namespace opencog; void FilterLink::init(void) { - // Maps consist of a function, and the data to apply the function to. - // The function can be explicit (inheriting from ScopeLink) or - // implicit (we automatically fish out free variables). + // Filters consist of a function, and the data to apply the + // function to. The function can be explicit (inheriting from + // ScopeLink) or implicit (we automatically fish out free variables). if (2 != _outgoing.size()) throw SyntaxException(TRACE_INFO, "FilterLink is expected to be arity-2 only!"); diff --git a/opencog/atoms/core/FreeVariables.cc b/opencog/atoms/core/FreeVariables.cc index c1df6b35eb..88a414a496 100644 --- a/opencog/atoms/core/FreeVariables.cc +++ b/opencog/atoms/core/FreeVariables.cc @@ -412,7 +412,7 @@ void FreeVariables::canonical_sort(const HandleSeq& hs) // Get free variables HandleSet fv = get_free_variables(hs); - // Ignore free variables in body not in the FreeVariables object + // Ignore free variables in the body that are not in this object. HandleSet ignored_vars = set_symmetric_difference(fv, varset); Context ctx(Quotation(), ignored_vars, false); diff --git a/opencog/atoms/core/FreeVariables.h b/opencog/atoms/core/FreeVariables.h index 5de670e4f1..b7d9168397 100644 --- a/opencog/atoms/core/FreeVariables.h +++ b/opencog/atoms/core/FreeVariables.h @@ -105,16 +105,14 @@ struct FreeVariables : Replacement /// ordered link. void find_variables(const HandleSeq& oset, bool ordered_link=true); - /// Sort the variables in a canonical order determined by their - /// positions in the given outgoing set, which is assumed ordered, - /// as outgoing sets of scopes are always ordered so far. In - /// ordered link, the ordered is determined by the outgoing set - /// order (from left to right). In unordered links, the ordered is - /// determined by some arbitrary, though semantically consistent - /// fix order. The order only depends on variable names as last - /// resort, when no semantic property can be used to break the - /// symmetry. - void canonical_sort(const HandleSeq& outgoings); + /// Sort the variables into a canonical order, so that they appear + /// in the same order as in the provided HandleSeq. That is, the + /// HandleSeq is presumed to be a list of trees, with variables + /// embeded in those trees. Each tree is walked, left-to-right, + /// depth-first. The order in which the variables are encountered + /// is the "canonical sort order". Behavior is undefined, if there + /// are variables that do NOT appear in the HandleSeq. + void canonical_sort(const HandleSeq&); /// Convert a variable->argument mapping into a sequence of /// "arguments" that are in the same order as the free variables From a153699b2ae8833c29577886c68b57a06c179e69 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 13:36:06 -0600 Subject: [PATCH 06/21] Add another variable-trimming utility --- opencog/atoms/core/FreeVariables.h | 4 ++-- opencog/atoms/core/Variables.cc | 18 ++++++++++++++++++ opencog/atoms/core/Variables.h | 3 +++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/opencog/atoms/core/FreeVariables.h b/opencog/atoms/core/FreeVariables.h index b7d9168397..fa11ff3096 100644 --- a/opencog/atoms/core/FreeVariables.h +++ b/opencog/atoms/core/FreeVariables.h @@ -110,8 +110,8 @@ struct FreeVariables : Replacement /// HandleSeq is presumed to be a list of trees, with variables /// embeded in those trees. Each tree is walked, left-to-right, /// depth-first. The order in which the variables are encountered - /// is the "canonical sort order". Behavior is undefined, if there - /// are variables that do NOT appear in the HandleSeq. + /// is the "canonical sort order". Variables that do NOT appear + /// in the HandleSeq are trimmed (removed) from this object. void canonical_sort(const HandleSeq&); /// Convert a variable->argument mapping into a sequence of diff --git a/opencog/atoms/core/Variables.cc b/opencog/atoms/core/Variables.cc index 412d2a151d..ca3b6b637e 100644 --- a/opencog/atoms/core/Variables.cc +++ b/opencog/atoms/core/Variables.cc @@ -571,6 +571,24 @@ void Variables::trim(const Handle& term) erase(hu); } +// Identical to above, except multiple terms are scanned. +void Variables::trim(const HandleSeq& terms) +{ + // Find the vars in all of the terms. + FreeVariables fv; + fv.find_variables(terms); + + // Find all vars not in any of the terms. + HandleSeq unused; + for (const Handle& hv: varseq) + if (not fv.varset_contains(hv)) + unused.push_back(hv); + + // Get rid of all vars not in any of the terms. + for (const Handle& hu: unused) + erase(hu); +} + /* ================================================================= */ /// Return true if the other Variables struct is equal to this one, diff --git a/opencog/atoms/core/Variables.h b/opencog/atoms/core/Variables.h index 1f99197572..4bcb70a917 100644 --- a/opencog/atoms/core/Variables.h +++ b/opencog/atoms/core/Variables.h @@ -158,6 +158,9 @@ struct Variables : public FreeVariables /// Remove *all* variables that do not appear in the term. void trim(const Handle&); + /// Remove *all* variables that do not appear in any of the terms. + void trim(const HandleSeq&); + /// Return the TypedVariableLink for the indicated variable. /// Return just the Variable itself, if its not typed. Handle get_type_decl(const Handle&, const Handle&) const; From 3c2cf7b1ce6fa999c206b09cf98aa256a61d695a Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 13:40:18 -0600 Subject: [PATCH 07/21] Export a variable-trimmer utility. --- opencog/atoms/core/ScopeLink.cc | 9 ++++++++- opencog/atoms/core/ScopeLink.h | 10 ++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/opencog/atoms/core/ScopeLink.cc b/opencog/atoms/core/ScopeLink.cc index b9feda82f3..4661a528b2 100644 --- a/opencog/atoms/core/ScopeLink.cc +++ b/opencog/atoms/core/ScopeLink.cc @@ -23,8 +23,8 @@ #include -// #include #include + #include #include #include @@ -181,6 +181,13 @@ void ScopeLink::init_scoped_variables(const Handle& vardecl) /* ================================================================= */ +void ScopeLink::trim(const HandleSeq& terms) +{ + _variables.trim(terms); +} + +/* ================================================================= */ + inline Handle append_rand_str(const Handle& var) { std::string new_var_name = randstr(var->get_name() + "-"); diff --git a/opencog/atoms/core/ScopeLink.h b/opencog/atoms/core/ScopeLink.h index 09beb26153..29ab323a5b 100644 --- a/opencog/atoms/core/ScopeLink.h +++ b/opencog/atoms/core/ScopeLink.h @@ -81,14 +81,20 @@ class ScopeLink : public Link const Handle& get_vardecl(void) const { return _vardecl; } const Handle& get_body(void) const { return _body; } + // Remove any variables that do NOT appear anywhere in the provided + // HandleSeq. This can be used to clean up vardecls, when variables + // are declared but then never used (thus making them impossible to + // ground, or having other nasty side-effects.) + void trim(const HandleSeq&); + // Return an alpha-converted copy of this atom. Optionally, new // variable names can be provided. If none are provided, then new // randomly generated names are created. // - // Warning: the atomspace treats all alpha-convertible atoms as + // Warning: the AtomSpace treats all alpha-convertible atoms as // identical; if the new copy is inserted into the atomspace, the // original version will be returned. Alpha-converted atoms can - // only be used outside of the atomspace, for temporary operations. + // only be used outside of the AtomSpace, for temporary operations. Handle alpha_convert() const; Handle alpha_convert(const HandleSeq& vars) const; From d3d96ae4dca6a05a317bfb0c773cd5a9ff04b634 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 14:50:17 -0600 Subject: [PATCH 08/21] Remove unused variables before pattern matching --- opencog/atoms/core/FilterLink.cc | 7 +++++++ opencog/atoms/rule/RuleLink.cc | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/opencog/atoms/core/FilterLink.cc b/opencog/atoms/core/FilterLink.cc index 5f174df673..2ec6fa8923 100644 --- a/opencog/atoms/core/FilterLink.cc +++ b/opencog/atoms/core/FilterLink.cc @@ -87,6 +87,13 @@ void FilterLink::init(void) "Expecting ImplicationScopeLink of at least size 3."); _rewrite.push_back(impl[2]); } + + // The URE ControlPolicyUTest creates rules that declare + // variables that are never in the body. As a result, those + // variales can never be grounded during filtering. I don't + // understand why this happens; I think the URE needs to be + // fixed. In the meanwhile, we clean up here. + _pattern->trim({_pattern->get_body()}); } // Locate all GlobNodes in the pattern diff --git a/opencog/atoms/rule/RuleLink.cc b/opencog/atoms/rule/RuleLink.cc index bd9cef5290..2e8c94e078 100644 --- a/opencog/atoms/rule/RuleLink.cc +++ b/opencog/atoms/rule/RuleLink.cc @@ -122,6 +122,17 @@ void RuleLink::extract_variables(const HandleSeq& oset) _body = oset[boff]; for (size_t i=boff+1; i < sz; i++) _implicand.push_back(oset[i]); + + // Remove any declared variables that are NOT in the body! + // This is an "unusual" situation, except that the URE does + // this regularly, when it constructs rules on the fly. + // I don't know why. + if (1 == boff) + { + _implicand.push_back(_body), + trim(_implicand); + _implicand.pop_back(); + } } /* ================================================================= */ From 580fd5fd989b4cf7242e11c3cf1ee82b1b93364d Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 15:03:19 -0600 Subject: [PATCH 09/21] Simplify the grounding sequence --- opencog/atoms/core/FilterLink.cc | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/opencog/atoms/core/FilterLink.cc b/opencog/atoms/core/FilterLink.cc index 2ec6fa8923..0d30b40550 100644 --- a/opencog/atoms/core/FilterLink.cc +++ b/opencog/atoms/core/FilterLink.cc @@ -328,27 +328,17 @@ Handle FilterLink::rewrite_one(const Handle& cterm, AtomSpace* scratch) const if (not extract(_pattern->get_body(), term, valmap)) return Handle::UNDEFINED; - // Make sure each variable is grounded. Place the groundings - // into a sequence, for easy access. Not all variables need to - // be grounded, because the re-write might not use all variables. - // If it does use a variable, it must have a grounding. - bool partial = false; + // Place the groundings into a sequence, for easy access. HandleSeq valseq; for (const Handle& var : _mvars->varseq) { auto valpair = valmap.find(var); - if (valmap.end() == valpair) - { - partial = true; - valseq.emplace_back(Handle::UNDEFINED); - } - else - valseq.emplace_back(valpair->second); - } - // Make sure each variable is grounded. (for real, this time) - if (partial) - return Handle::UNDEFINED; + // Can't ever happen. + // if (valmap.end() == valpair) return Handle::UNDEFINED; + + valseq.emplace_back(valpair->second); + } // Perform substitution, if it's a RuleLink. if (not _rewrite.empty()) From 87a3425eb6f64e2d577f95c765d7e80c86b8a7b6 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 15:13:42 -0600 Subject: [PATCH 10/21] Unit test: unused variables handled automatically. --- tests/query/DisconnectedUTest.cxxtest | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/query/DisconnectedUTest.cxxtest b/tests/query/DisconnectedUTest.cxxtest index d90c21cd9e..04d634dc35 100644 --- a/tests/query/DisconnectedUTest.cxxtest +++ b/tests/query/DisconnectedUTest.cxxtest @@ -143,7 +143,9 @@ void DisconnectedUTest::test_variables(void) } // Similar to above, except that the stuff is built up in C++ not in -// scheme. See bug #172. +// scheme. See bug #172. Note: new trimming code automatically +// and silently removes declared variables that do not appear in the +// body. This avoids crazy side-effects and crashes in the URE. void DisconnectedUTest::test_cvariables(void) { logger().debug("BEGIN TEST: %s", __FUNCTION__); @@ -152,6 +154,7 @@ void DisconnectedUTest::test_cvariables(void) bool caught = false; try { + // Variable B is bound, but is never used in the body. Handle va(createNode(VARIABLE_NODE, "$A")); Handle vb(createNode(VARIABLE_NODE, "$B")); Handle blv(createLink(VARIABLE_LIST, va, vb)); @@ -166,7 +169,7 @@ void DisconnectedUTest::test_cvariables(void) caught = true; } logger().info("Caught exception? %d\n", caught); - TSM_ASSERT("Failed to catch expected exception", caught); + // TSM_ASSERT("Failed to catch expected exception", caught); logger().debug("END TEST: %s", __FUNCTION__); } From 9081db9575ac78c225af3be36f7a4b113bd44565 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 16:18:20 -0600 Subject: [PATCH 11/21] iStart work to simplify the execution process --- opencog/atoms/core/FilterLink.cc | 8 ++++---- opencog/object-atomese/README.md | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/opencog/atoms/core/FilterLink.cc b/opencog/atoms/core/FilterLink.cc index 0d30b40550..915d907480 100644 --- a/opencog/atoms/core/FilterLink.cc +++ b/opencog/atoms/core/FilterLink.cc @@ -321,7 +321,7 @@ Handle FilterLink::rewrite_one(const Handle& cterm, AtomSpace* scratch) const // Execute the ground, including consuming its quotation as part of // the FilterLink semantics Instantiator inst(scratch); - Handle term(HandleCast(inst.instantiate(cterm, GroundingMap()))); + Handle term(HandleCast(inst.execute(cterm))); // Extract values for variables. GroundingMap valmap; @@ -370,9 +370,9 @@ ValuePtr FilterLink::execute(AtomSpace* as, bool silent) const Handle& valh = _outgoing[1]; // Handle three different cases. - // If there is a single value, apply the map to the single value. - // If there is a set of values, apply the map to the set. - // If there is a list of values, apply the map to the list. + // If there is a single value, apply the filter to the single value. + // If there is a set of values, apply the filter to the set. + // If there is a list of values, apply the filter to the list. Type argtype = valh->get_type(); if (SET_LINK == argtype or LIST_LINK == argtype) { diff --git a/opencog/object-atomese/README.md b/opencog/object-atomese/README.md index 38d8af9a3c..9eb3c56bfa 100644 --- a/opencog/object-atomese/README.md +++ b/opencog/object-atomese/README.md @@ -239,7 +239,7 @@ TODO ---- * Implement IncomingSet Of. See #2752 for API * Modernize FilterLink. Make sure it can work with LinkValues, and so that - it works like a filter link. See #2201 + it works like a filter link. * Handle SignLink See issue #2602 * Handle Signatures in the pattern matcher, plus examples & tests. * Change BoolValue so it can create maskes from bit-specs!? From 7e60ad1658fae8870ddcb4ec1e2365a9b78835a5 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 17:49:08 -0600 Subject: [PATCH 12/21] Reduce the power --- opencog/atoms/grounded/GroundedSchemaNode.cc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/opencog/atoms/grounded/GroundedSchemaNode.cc b/opencog/atoms/grounded/GroundedSchemaNode.cc index f4d01d5c3f..8b32a058e0 100644 --- a/opencog/atoms/grounded/GroundedSchemaNode.cc +++ b/opencog/atoms/grounded/GroundedSchemaNode.cc @@ -114,21 +114,23 @@ ValuePtr GroundedSchemaNode::execute(AtomSpace* as, const Handle& cargs, bool silent) { + // Unknown procedure type + if (nullptr == _runner) + throw RuntimeException(TRACE_INFO, + "Cannot evaluate unknown Schema %s", + to_short_string().c_str()); + LAZY_LOG_FINE << "Execute gsn: " << to_short_string() << "with arguments: " << oc_to_string(cargs); // Perform "eager evaluation" instead of "lazy evaluation". - if (_eager and _runner) + if (_eager) { Handle exargs(force_execute(as, cargs, silent)); return _runner->execute(as, exargs, silent); } - if (_runner) return _runner->execute(as, cargs, silent); - // Unknown procedure type - throw RuntimeException(TRACE_INFO, - "Cannot evaluate unknown Schema %s", - to_short_string().c_str()); + return _runner->execute(as, cargs, silent); } DEFINE_NODE_FACTORY(GroundedSchemaNode, GROUNDED_SCHEMA_NODE) From f6190a943162478f73ce99e229beb88a5fd1bd76 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 18:57:37 -0600 Subject: [PATCH 13/21] Wire in support for Values --- opencog/atoms/core/FilterLink.cc | 40 ++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/opencog/atoms/core/FilterLink.cc b/opencog/atoms/core/FilterLink.cc index 915d907480..c9a6643389 100644 --- a/opencog/atoms/core/FilterLink.cc +++ b/opencog/atoms/core/FilterLink.cc @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include "FilterLink.h" @@ -367,12 +369,37 @@ Handle FilterLink::rewrite_one(const Handle& cterm, AtomSpace* scratch) const ValuePtr FilterLink::execute(AtomSpace* as, bool silent) { - const Handle& valh = _outgoing[1]; + Handle valh(_outgoing[1]); + + if (valh->is_executable()) + { + ValuePtr vex = valh->execute(); + + // XXX TODO FIXME -- if vex is a stream, e.g. a QueueValue, + // then we should construct another Queue as the return value, + // and perform filtering on-demand. + if (vex->is_type(LINK_VALUE)) + { + HandleSeq remap; + for (const Handle& h : LinkValueCast(vex)->to_handle_seq()) + { + Handle mone = rewrite_one(h, as); + if (nullptr != mone) remap.emplace_back(mone); + } + return createLinkValue(remap); + } + + // If it is some other Value, we have no clue what to do with it. + if (not vex->is_atom()) + return createVoidValue(); + + // Fall through, if execution provided some Atom. + } // Handle three different cases. - // If there is a single value, apply the filter to the single value. - // If there is a set of values, apply the filter to the set. - // If there is a list of values, apply the filter to the list. + // If there is a single Atom, apply the filter to the single Atom. + // If there is a set of Atoms, apply the filter to the set. + // If there is a list of Atoms, apply the filter to the list. Type argtype = valh->get_type(); if (SET_LINK == argtype or LIST_LINK == argtype) { @@ -389,9 +416,8 @@ ValuePtr FilterLink::execute(AtomSpace* as, bool silent) Handle mone = rewrite_one(valh, as); if (mone) return mone; - // Avoid returning null handle. This is broken. - // I don't like FilterLink much any more. - return as->add_link(SET_LINK); + // Avoid returning null pointer!? + return createVoidValue(); } DEFINE_LINK_FACTORY(FilterLink, FILTER_LINK) From c247420b7e08d3bb69241e9d762dbfa9d6385069 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 19:06:25 -0600 Subject: [PATCH 14/21] Minor fixes --- opencog/atoms/core/FilterLink.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/opencog/atoms/core/FilterLink.cc b/opencog/atoms/core/FilterLink.cc index c9a6643389..b20d2f7dc5 100644 --- a/opencog/atoms/core/FilterLink.cc +++ b/opencog/atoms/core/FilterLink.cc @@ -394,6 +394,7 @@ ValuePtr FilterLink::execute(AtomSpace* as, bool silent) return createVoidValue(); // Fall through, if execution provided some Atom. + valh = HandleCast(vex); } // Handle three different cases. @@ -416,7 +417,11 @@ ValuePtr FilterLink::execute(AtomSpace* as, bool silent) Handle mone = rewrite_one(valh, as); if (mone) return mone; - // Avoid returning null pointer!? + // Avoid returning null pointer! + // If we were given Atoms, assum the caller wants Atoms back. + // Otherwise, avoid polution and return VoidValue. + if (valh->is_atom()) + return as->add_link(SET_LINK); return createVoidValue(); } From f2a234be34aa9e707a03bd20c9eae449fd704650 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 19:15:31 -0600 Subject: [PATCH 15/21] Pass the silent arg --- opencog/atoms/core/FilterLink.cc | 9 +++++---- opencog/atoms/core/FilterLink.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/opencog/atoms/core/FilterLink.cc b/opencog/atoms/core/FilterLink.cc index b20d2f7dc5..7823607da8 100644 --- a/opencog/atoms/core/FilterLink.cc +++ b/opencog/atoms/core/FilterLink.cc @@ -318,7 +318,8 @@ bool FilterLink::extract(const Handle& termpat, return (ip == tsz) and (jg == gsz); } -Handle FilterLink::rewrite_one(const Handle& cterm, AtomSpace* scratch) const +Handle FilterLink::rewrite_one(const Handle& cterm, + AtomSpace* scratch, bool silent) const { // Execute the ground, including consuming its quotation as part of // the FilterLink semantics @@ -383,7 +384,7 @@ ValuePtr FilterLink::execute(AtomSpace* as, bool silent) HandleSeq remap; for (const Handle& h : LinkValueCast(vex)->to_handle_seq()) { - Handle mone = rewrite_one(h, as); + Handle mone = rewrite_one(h, as, silent); if (nullptr != mone) remap.emplace_back(mone); } return createLinkValue(remap); @@ -407,14 +408,14 @@ ValuePtr FilterLink::execute(AtomSpace* as, bool silent) HandleSeq remap; for (const Handle& h : valh->getOutgoingSet()) { - Handle mone = rewrite_one(h, as); + Handle mone = rewrite_one(h, as, silent); if (nullptr != mone) remap.emplace_back(mone); } return as->add_link(argtype, std::move(remap)); } // Its a singleton. Just remap that. - Handle mone = rewrite_one(valh, as); + Handle mone = rewrite_one(valh, as, silent); if (mone) return mone; // Avoid returning null pointer! diff --git a/opencog/atoms/core/FilterLink.h b/opencog/atoms/core/FilterLink.h index 036699fc2e..7b7e3c08ca 100644 --- a/opencog/atoms/core/FilterLink.h +++ b/opencog/atoms/core/FilterLink.h @@ -60,7 +60,7 @@ class FilterLink : public FunctionLink bool extract(const Handle&, const Handle&, GroundingMap&, Quotation quotation=Quotation()) const; - Handle rewrite_one(const Handle&, AtomSpace*) const; + Handle rewrite_one(const Handle&, AtomSpace*, bool) const; public: FilterLink(const HandleSeq&&, Type=FILTER_LINK); From 5aba872cefc9daefa2b5aba13282ec9f095f5e7f Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 19:20:37 -0600 Subject: [PATCH 16/21] Start getting rid of the instantiator --- opencog/atoms/core/FilterLink.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/opencog/atoms/core/FilterLink.cc b/opencog/atoms/core/FilterLink.cc index 7823607da8..fcdabe788f 100644 --- a/opencog/atoms/core/FilterLink.cc +++ b/opencog/atoms/core/FilterLink.cc @@ -318,6 +318,8 @@ bool FilterLink::extract(const Handle& termpat, return (ip == tsz) and (jg == gsz); } +// ==================================================================== + Handle FilterLink::rewrite_one(const Handle& cterm, AtomSpace* scratch, bool silent) const { @@ -348,11 +350,14 @@ Handle FilterLink::rewrite_one(const Handle& cterm, { HandleSeq rew; // Beta reduce, and execute. No type-checking during - // beta-reduction; we've already done that. + // beta-reduction; we've already done that, during matching. for (const Handle& impl : _rewrite) { Handle red(_mvars->substitute_nocheck(impl, valseq)); - rew.emplace_back(HandleCast(inst.execute(red))); + if (red->is_executable()) + rew.emplace_back(HandleCast(red->execute(scratch, silent))); + else + rew.emplace_back(red); } valseq.swap(rew); From c66e1d40f40c3eb119ac6f65172ccc4c13ff8780 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 19:38:32 -0600 Subject: [PATCH 17/21] Provide a better explanation of what's going on. --- opencog/atoms/core/FilterLink.cc | 23 +++++++++++++------ tests/atoms/execution/FilterLinkUTest.cxxtest | 3 ++- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/opencog/atoms/core/FilterLink.cc b/opencog/atoms/core/FilterLink.cc index fcdabe788f..988e3dd1ae 100644 --- a/opencog/atoms/core/FilterLink.cc +++ b/opencog/atoms/core/FilterLink.cc @@ -157,9 +157,9 @@ FilterLink::FilterLink(const HandleSeq&& oset, Type t) /// is returned, valmap contains the extracted values. /// bool FilterLink::extract(const Handle& termpat, - const Handle& ground, - GroundingMap& valmap, - Quotation quotation) const + const Handle& ground, + GroundingMap& valmap, + Quotation quotation) const { if (termpat == ground) return true; @@ -323,12 +323,21 @@ bool FilterLink::extract(const Handle& termpat, Handle FilterLink::rewrite_one(const Handle& cterm, AtomSpace* scratch, bool silent) const { - // Execute the ground, including consuming its quotation as part of - // the FilterLink semantics + // Execute the term, first. We use the Instantiator to perform + // a "deep" execution, executing stuff deep within the term. + // This includes the consumption of embedded QuoteLinks. But why? + // I dunno; this is an older design decision, motivated by the URE. + // Is it a good design decision? I dunno. For now, there's not + // enough experience to say. + // + // Also, FYI, we could do execution in-line with extraction, + // above. This would improve performance and avoid un-needed + // execution. Instantiator inst(scratch); - Handle term(HandleCast(inst.execute(cterm))); + Handle term(HandleCast(inst.execute(cterm, silent))); - // Extract values for variables. + // See it the term passes pattern matching. If it does, the + // side effect is that we get a grounding map as output. GroundingMap valmap; if (not extract(_pattern->get_body(), term, valmap)) return Handle::UNDEFINED; diff --git a/tests/atoms/execution/FilterLinkUTest.cxxtest b/tests/atoms/execution/FilterLinkUTest.cxxtest index 742c7c8f20..fc91bbb218 100644 --- a/tests/atoms/execution/FilterLinkUTest.cxxtest +++ b/tests/atoms/execution/FilterLinkUTest.cxxtest @@ -223,7 +223,8 @@ void FilterLinkUTest::test_implication(void) result = eval->eval_h("(cog-execute! imply-eval)"); sete = eval->eval_h("eval-expected"); - printf("got %s", result->to_string().c_str()); + printf("--------\n"); + printf("got %s\n", result->to_string().c_str()); printf("expected %s\n", sete->to_string().c_str()); TS_ASSERT(result == sete); From 224c574674fe9460a0c054e9d5c52b9cd06a9c1c Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 19:55:11 -0600 Subject: [PATCH 18/21] Avoid using the instantiator --- opencog/atoms/core/FilterLink.cc | 57 +++++++++++++++++--------------- opencog/atoms/core/FilterLink.h | 1 + 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/opencog/atoms/core/FilterLink.cc b/opencog/atoms/core/FilterLink.cc index 988e3dd1ae..ddc04efd35 100644 --- a/opencog/atoms/core/FilterLink.cc +++ b/opencog/atoms/core/FilterLink.cc @@ -19,10 +19,10 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include #include #include -#include #include #include #include @@ -157,11 +157,28 @@ FilterLink::FilterLink(const HandleSeq&& oset, Type t) /// is returned, valmap contains the extracted values. /// bool FilterLink::extract(const Handle& termpat, - const Handle& ground, + const Handle& gnd, GroundingMap& valmap, + AtomSpace* scratch, bool silent, Quotation quotation) const { - if (termpat == ground) return true; + if (termpat == gnd) return true; + + // Execute the proposed grounding term, first. Notice that this is + // a "deep" execution, because there may have been lots of + // non-executable stuff above us. Is this deep execution actually + // a good idea? I dunno; this is an older design decision, motivated + // by the URE. Is it a good design decision? I dunno. For now, there's + // not enough experience to say. There is, however, a unit test to + // check this behavior. + Handle ground; + if (gnd->is_executable()) + { + ground = HandleCast(gnd->execute(scratch, silent)); + if (nullptr == ground) return false; + } + else + ground = gnd; Type t = termpat->get_type(); // If its a variable, then see if we know its value already; @@ -189,9 +206,8 @@ bool FilterLink::extract(const Handle& termpat, // Consume quotation if (quotation_cp.consumable(t)) - { - return extract(termpat->getOutgoingAtom(0), ground, valmap, quotation); - } + return extract(termpat->getOutgoingAtom(0), ground, valmap, + scratch, silent, quotation); if (GLOB_NODE == t and 0 < _varset->count(termpat)) { @@ -208,7 +224,7 @@ bool FilterLink::extract(const Handle& termpat, { for (const Handle& choice : termpat->getOutgoingSet()) { - if (extract(choice, ground, valmap, quotation)) + if (extract(choice, ground, valmap, scratch, silent, quotation)) return true; } return false; @@ -233,7 +249,7 @@ bool FilterLink::extract(const Handle& termpat, if (gsz != tsz) return false; for (size_t i=0; iget_body(), term, valmap)) + if (not extract(_pattern->get_body(), cterm, valmap, scratch, silent)) return Handle::UNDEFINED; // Place the groundings into a sequence, for easy access. diff --git a/opencog/atoms/core/FilterLink.h b/opencog/atoms/core/FilterLink.h index 7b7e3c08ca..558e21c6f3 100644 --- a/opencog/atoms/core/FilterLink.h +++ b/opencog/atoms/core/FilterLink.h @@ -58,6 +58,7 @@ class FilterLink : public FunctionLink FilterLink(Type, const Handle&); bool extract(const Handle&, const Handle&, GroundingMap&, + AtomSpace*, bool, Quotation quotation=Quotation()) const; Handle rewrite_one(const Handle&, AtomSpace*, bool) const; From 090b9ab7048402b19cb1938e840196ab7f385242 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 20:06:15 -0600 Subject: [PATCH 19/21] Consume quotations, as promised. --- opencog/atoms/core/FilterLink.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/opencog/atoms/core/FilterLink.cc b/opencog/atoms/core/FilterLink.cc index ddc04efd35..7c2a07d3dc 100644 --- a/opencog/atoms/core/FilterLink.cc +++ b/opencog/atoms/core/FilterLink.cc @@ -369,9 +369,17 @@ Handle FilterLink::rewrite_one(const Handle& cterm, if (red->is_executable()) rew.emplace_back(HandleCast(red->execute(scratch, silent))); else - rew.emplace_back(red); + { + // Consume quotations. + Type rty = red->get_type(); + if (LOCAL_QUOTE_LINK == rty or DONT_EXEC_LINK == rty) + rew.emplace_back(red->getOutgoingAtom(0)); + else + rew.emplace_back(red); + } } + // Fall through, use the same logic to finish up. valseq.swap(rew); } From f4c1d174d2caa5b75f4bbe5df508d6f6c602df28 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 20:18:12 -0600 Subject: [PATCH 20/21] Move FilterLink from core to flow library --- opencog/atoms/core/CMakeLists.txt | 2 -- opencog/atoms/flow/CMakeLists.txt | 2 ++ opencog/atoms/{core => flow}/FilterLink.cc | 4 ++-- opencog/atoms/{core => flow}/FilterLink.h | 4 ++-- tests/atoms/execution/CMakeLists.txt | 1 - tests/atoms/flow/CMakeLists.txt | 3 +++ .../FilterLinkUTest.cxxtest | 18 +++++++++--------- .../atoms/{execution => flow}/filter-link.scm | 0 8 files changed, 18 insertions(+), 16 deletions(-) rename opencog/atoms/{core => flow}/FilterLink.cc (99%) rename opencog/atoms/{core => flow}/FilterLink.h (96%) rename tests/atoms/{execution => flow}/FilterLinkUTest.cxxtest (93%) rename tests/atoms/{execution => flow}/filter-link.scm (100%) diff --git a/opencog/atoms/core/CMakeLists.txt b/opencog/atoms/core/CMakeLists.txt index 8f612b9abb..893033d257 100644 --- a/opencog/atoms/core/CMakeLists.txt +++ b/opencog/atoms/core/CMakeLists.txt @@ -9,7 +9,6 @@ ADD_LIBRARY (atomcore Context.cc DefineLink.cc DeleteLink.cc - FilterLink.cc FindUtils.cc FreeLink.cc FreeVariables.cc @@ -58,7 +57,6 @@ INSTALL (FILES Context.h DefineLink.h DeleteLink.h - FilterLink.h FindUtils.h FreeLink.h FreeVariables.h diff --git a/opencog/atoms/flow/CMakeLists.txt b/opencog/atoms/flow/CMakeLists.txt index 450aeb46c6..1f7337d6ae 100644 --- a/opencog/atoms/flow/CMakeLists.txt +++ b/opencog/atoms/flow/CMakeLists.txt @@ -3,6 +3,7 @@ INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR}) ADD_LIBRARY (atomflow + FilterLink.cc FormulaPredicateLink.cc NumberOfLink.cc PromiseLink.cc @@ -29,6 +30,7 @@ INSTALL (TARGETS atomflow EXPORT AtomSpaceTargets ) INSTALL (FILES + FilterLink.h FormulaPredicateLink.h NumberOfLink.h PromiseLink.h diff --git a/opencog/atoms/core/FilterLink.cc b/opencog/atoms/flow/FilterLink.cc similarity index 99% rename from opencog/atoms/core/FilterLink.cc rename to opencog/atoms/flow/FilterLink.cc index 7c2a07d3dc..8db904dc32 100644 --- a/opencog/atoms/core/FilterLink.cc +++ b/opencog/atoms/flow/FilterLink.cc @@ -1,7 +1,7 @@ /* - * opencog/atoms/core/FilterLink.cc + * opencog/atoms/flow/FilterLink.cc * - * Copyright (C) 2015, 2016 Linas Vepstas + * Copyright (C) 2015, 2016, 2022 Linas Vepstas * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License v3 as diff --git a/opencog/atoms/core/FilterLink.h b/opencog/atoms/flow/FilterLink.h similarity index 96% rename from opencog/atoms/core/FilterLink.h rename to opencog/atoms/flow/FilterLink.h index 558e21c6f3..f6e8dcf75f 100644 --- a/opencog/atoms/core/FilterLink.h +++ b/opencog/atoms/flow/FilterLink.h @@ -1,7 +1,7 @@ /* - * opencog/atoms/core/FilterLink.h + * opencog/atoms/flow/FilterLink.h * - * Copyright (C) 2015,2016 Linas Vepstas + * Copyright (C) 2015,2016,2022 Linas Vepstas * All Rights Reserved * * This program is free software; you can redistribute it and/or modify diff --git a/tests/atoms/execution/CMakeLists.txt b/tests/atoms/execution/CMakeLists.txt index 98eca4219f..ec1b160630 100644 --- a/tests/atoms/execution/CMakeLists.txt +++ b/tests/atoms/execution/CMakeLists.txt @@ -1,4 +1,3 @@ LINK_LIBRARIES(execution smob atomspace) ADD_CXXTEST(DefinedSchemaUTest) -ADD_CXXTEST(FilterLinkUTest) diff --git a/tests/atoms/flow/CMakeLists.txt b/tests/atoms/flow/CMakeLists.txt index 05b10cac8d..c48ebd2e38 100644 --- a/tests/atoms/flow/CMakeLists.txt +++ b/tests/atoms/flow/CMakeLists.txt @@ -18,3 +18,6 @@ TARGET_LINK_LIBRARIES(SetValueUTest execution smob) ADD_CXXTEST(DynamicUTest) TARGET_LINK_LIBRARIES(DynamicUTest execution smob) + +ADD_CXXTEST(FilterLinkUTest) +TARGET_LINK_LIBRARIES(FilterLinkUTest execution smob) diff --git a/tests/atoms/execution/FilterLinkUTest.cxxtest b/tests/atoms/flow/FilterLinkUTest.cxxtest similarity index 93% rename from tests/atoms/execution/FilterLinkUTest.cxxtest rename to tests/atoms/flow/FilterLinkUTest.cxxtest index fc91bbb218..8dc6e0624f 100644 --- a/tests/atoms/execution/FilterLinkUTest.cxxtest +++ b/tests/atoms/flow/FilterLinkUTest.cxxtest @@ -1,5 +1,5 @@ /* - * tests/atoms/FilterLinkUTest.cxxtest + * tests/atoms/flow/FilterLinkUTest.cxxtest * * Copyright (C) 2016 Linas Vepstas * All Rights Reserved @@ -83,7 +83,7 @@ void FilterLinkUTest::test_singleton(void) { logger().debug("BEGIN TEST: %s", __FUNCTION__); - eval->eval("(load-from-path \"tests/atoms/execution/filter-link.scm\")"); + eval->eval("(load-from-path \"tests/atoms/flow/filter-link.scm\")"); Handle result = eval->eval_h("(cog-execute! single)"); @@ -162,7 +162,7 @@ void FilterLinkUTest::test_signature(void) { logger().debug("BEGIN TEST: %s", __FUNCTION__); - eval->eval("(load-from-path \"tests/atoms/execution/filter-link.scm\")"); + eval->eval("(load-from-path \"tests/atoms/flow/filter-link.scm\")"); Handle result = eval->eval_h("(cog-execute! single-signature)"); @@ -179,7 +179,7 @@ void FilterLinkUTest::test_double_set(void) { logger().debug("BEGIN TEST: %s", __FUNCTION__); - eval->eval("(load-from-path \"tests/atoms/execution/filter-link.scm\")"); + eval->eval("(load-from-path \"tests/atoms/flow/filter-link.scm\")"); Handle result = eval->eval_h("(cog-execute! double-num-set)"); @@ -209,7 +209,7 @@ void FilterLinkUTest::test_implication(void) { logger().debug("BEGIN TEST: %s", __FUNCTION__); - eval->eval("(load-from-path \"tests/atoms/execution/filter-link.scm\")"); + eval->eval("(load-from-path \"tests/atoms/flow/filter-link.scm\")"); Handle result = eval->eval_h("(cog-execute! imply-map)"); @@ -236,7 +236,7 @@ void FilterLinkUTest::test_glob(void) { logger().debug("BEGIN TEST: %s", __FUNCTION__); - eval->eval("(load-from-path \"tests/atoms/execution/filter-link.scm\")"); + eval->eval("(load-from-path \"tests/atoms/flow/filter-link.scm\")"); Handle result = eval->eval_h("(cog-execute! glob-simple)"); @@ -280,7 +280,7 @@ void FilterLinkUTest::test_implication_nodecl(void) { logger().debug("BEGIN TEST: %s", __FUNCTION__); - eval->eval("(load-from-path \"tests/atoms/execution/filter-link.scm\")"); + eval->eval("(load-from-path \"tests/atoms/flow/filter-link.scm\")"); Handle result = eval->eval_h("(cog-execute! imply-map-nodecl)"); @@ -304,7 +304,7 @@ void FilterLinkUTest::test_local_quote_map(void) { logger().debug("BEGIN TEST: %s", __FUNCTION__); - eval->eval("(load-from-path \"tests/atoms/execution/filter-link.scm\")"); + eval->eval("(load-from-path \"tests/atoms/flow/filter-link.scm\")"); Instantiator inst(as.get()); Handle local_quote_map = eval->eval_h("local-quote-map"), @@ -325,7 +325,7 @@ void FilterLinkUTest::xtest_quote_arg_map(void) { logger().debug("BEGIN TEST: %s", __FUNCTION__); - eval->eval("(load-from-path \"tests/atoms/execution/filter-link.scm\")"); + eval->eval("(load-from-path \"tests/atoms/flow/filter-link.scm\")"); Instantiator inst(as.get()); Handle quote_arg_map = eval->eval_h("quote-arg-map"), diff --git a/tests/atoms/execution/filter-link.scm b/tests/atoms/flow/filter-link.scm similarity index 100% rename from tests/atoms/execution/filter-link.scm rename to tests/atoms/flow/filter-link.scm From 9f3b8ea7bbf89c2c362525dfd4dfe602feaee3e7 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 15 Dec 2022 20:32:16 -0600 Subject: [PATCH 21/21] Remove a TODO list item --- opencog/object-atomese/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/opencog/object-atomese/README.md b/opencog/object-atomese/README.md index 9eb3c56bfa..13c5abd89f 100644 --- a/opencog/object-atomese/README.md +++ b/opencog/object-atomese/README.md @@ -238,8 +238,6 @@ Also useful would be `IncomingSetOf` which would return a `LinkValue`. TODO ---- * Implement IncomingSet Of. See #2752 for API -* Modernize FilterLink. Make sure it can work with LinkValues, and so that - it works like a filter link. * Handle SignLink See issue #2602 * Handle Signatures in the pattern matcher, plus examples & tests. * Change BoolValue so it can create maskes from bit-specs!?