From d5898fb3e3059bcc098fb438b7c40ce10df772ad Mon Sep 17 00:00:00 2001 From: Kasim Date: Fri, 11 Dec 2020 15:25:23 +0300 Subject: [PATCH 1/7] Add ignore param on shallow specialization formula --- opencog/miner/miner-utils.scm | 29 ++++++++++++------- .../miner/rules/shallow-specialization.scm | 12 ++++---- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/opencog/miner/miner-utils.scm b/opencog/miner/miner-utils.scm index 4325947a2..305311a84 100644 --- a/opencog/miner/miner-utils.scm +++ b/opencog/miner/miner-utils.scm @@ -175,7 +175,8 @@ maximum-variables maximum-spcial-conjuncts type-check - glob-support) + glob-support + ignore) (define mv (min 9 maximum-variables)) ;; Only define such rules if maximum-spcial-conjuncts if above 0 @@ -192,7 +193,7 @@ (definify (lambda (i) (DefineLink (aliasify i) - (gen-shallow-specialization-rule i mv type-check glob-support)))) + (gen-shallow-specialization-rule i mv type-check glob-support ignore)))) (rule-tv (stv 0.9 1)) (rulify (lambda (i) (definify i) (list (aliasify i) rule-tv))) (rules (map rulify (iota-plus-one maximum-spcial-conjuncts)))) @@ -245,13 +246,15 @@ (maximum-spcial-conjuncts default-maximum-spcial-conjuncts) (maximum-cnjexp-variables default-maximum-cnjexp-variables) (type-check default-type-check) - (glob-support default-glob-support)) + (glob-support default-glob-support) + (ignore default-ignore)) ;; Load shallow specialization and associate to pm-rbs (configure-shallow-specialization-rules pm-rbs maximum-variables maximum-spcial-conjuncts type-check - glob-support) + glob-support + ignore) ;; Load conjunction-expansion and associate to pm-rbs (configure-conjunction-expansion-rules pm-rbs @@ -269,7 +272,8 @@ (maximum-spcial-conjuncts default-maximum-spcial-conjuncts) (maximum-cnjexp-variables default-maximum-cnjexp-variables) (type-check default-type-check) - (glob-support default-glob-support)) + (glob-support default-glob-support) + (ignore default-ignore)) (configure-mandatory-rules pm-rbs) (configure-optional-rules pm-rbs #:conjunction-expansion conjunction-expansion @@ -279,7 +283,8 @@ #:maximum-spcial-conjuncts maximum-spcial-conjuncts #:maximum-cnjexp-variables maximum-cnjexp-variables #:type-check type-check - #:glob-support glob-support)) + #:glob-support glob-support + #:ignore ignore)) (define* (configure-surprisingness surp-rbs mode maximum-conjuncts db-ratio) ;; Add surprisingness rules @@ -331,7 +336,8 @@ (maximum-spcial-conjuncts default-maximum-spcial-conjuncts) (maximum-cnjexp-variables default-maximum-cnjexp-variables) (type-check default-type-check) - (glob-support default-glob-support)) + (glob-support default-glob-support) + (ignore default-ignore)) " Given a Concept node representing a rule based system for the pattern miner. Automatically configure it with the appropriate @@ -396,7 +402,8 @@ #:maximum-spcial-conjuncts maximum-spcial-conjuncts #:maximum-cnjexp-variables maximum-cnjexp-variables #:type-check type-check - #:glob-support glob-support) + #:glob-support glob-support + #:ignore ignore) ;; Set parameters (ure-set-jobs pm-rbs jobs) @@ -611,7 +618,8 @@ ;; enable type-check (type-check default-type-check) - (glob-support default-glob-support)) + (glob-support default-glob-support) + (ignore default-ignore)) " Mine patterns in db (data trees, a.k.a. grounded hypergraphs) with minimum support ms, optionally using mi iterations and starting from the initial @@ -984,7 +992,8 @@ #:maximum-spcial-conjuncts mspc #:maximum-cnjexp-variables mcev #:type-check type-check - #:glob-support glob-support)) + #:glob-support glob-support + #:ignore ignore)) (dummy (miner-logger-debug "Initial pattern:\n~a" (get-initial-pattern))) (dummy (miner-logger-debug "Has enough support (min support = ~a)" ms)) diff --git a/opencog/miner/rules/shallow-specialization.scm b/opencog/miner/rules/shallow-specialization.scm index b91226f89..105e59ce1 100644 --- a/opencog/miner/rules/shallow-specialization.scm +++ b/opencog/miner/rules/shallow-specialization.scm @@ -44,7 +44,7 @@ ;; ;; mv is the maximum number of variable allowed in the resulting ;; patterns. -(define (gen-shallow-specialization-rule nary mv type-check glob-support) +(define (gen-shallow-specialization-rule nary mv type-check glob-support ignore) (let* (;; Variables (pattern-vardecl (Variable "$vardecl")) (cnjs (gen-variables "$cnj" nary)) @@ -88,22 +88,24 @@ ; such. Or perhaps use Glob. minsup-pattern (cog-new-node 'PredicateNode "type-check" (cog-new-stv (btoi type-check) 1)) - (cog-new-node 'PredicateNode "glob-support" (cog-new-stv (btoi glob-support) 1))))))) + (cog-new-node 'PredicateNode "glob-support" (cog-new-stv (btoi glob-support) 1)) + ignore))))) ;; Shallow specialization formula ;; ;; mv is the maximimum number of variables (define (gen-shallow-specialization-formula mv) (lambda (conclusion . premises) - ;; (cog-logger-debug "gen-shallow-specialization-formula mv=~a, conclusion=~a, premises=~a" mv conclusion premises) - (if (= (length premises) 3) + (cog-logger-debug "gen-shallow-specialization-formula mv=~a, conclusion=~a, premises=~a" mv conclusion premises) + (if (= (length premises) 4) (let* ((minsup-pattern (car premises)) (type-check (cadr premises)) (glob-support (caddr premises)) + (ignore (cadddr premises)) (pattern (get-pattern minsup-pattern)) (db (get-db minsup-pattern)) (ms (get-ms minsup-pattern)) - (shaspes (cog-shallow-specialize pattern db ms (Number mv) type-check glob-support)) + (shaspes (cog-shallow-specialize pattern db ms (Number mv) type-check glob-support ignore)) (minsup-shaspe (lambda (x) (cog-set-tv! (minsup-eval x db ms) (stv 1 1)))) From d88e92680a7c200a420260d9e7e3041c1ee2a2b8 Mon Sep 17 00:00:00 2001 From: Kasim Date: Fri, 11 Dec 2020 15:29:46 +0300 Subject: [PATCH 2/7] Fetch ignore param --- opencog/miner/MinerSCM.cc | 9 ++++++--- opencog/miner/MinerUtils.cc | 15 +++++++++------ opencog/miner/MinerUtils.h | 9 ++++++--- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/opencog/miner/MinerSCM.cc b/opencog/miner/MinerSCM.cc index e0c29dc1f..95bf0db7c 100644 --- a/opencog/miner/MinerSCM.cc +++ b/opencog/miner/MinerSCM.cc @@ -83,7 +83,8 @@ class MinerSCM : public ModuleWrap */ Handle do_shallow_specialize(Handle pattern, Handle db, Handle ms, Handle mv, - Handle type_check, Handle glob_support); + Handle type_check, Handle glob_support, + Handle ignore); /** * Given a pattern, a db concept and a minimum support, return @@ -234,7 +235,8 @@ Handle MinerSCM::do_shallow_specialize(Handle pattern, Handle ms_h, Handle mv_h, Handle type_check, - Handle glob_support) + Handle glob_support, + Handle ignore) { AtomSpace *as = SchemeSmob::ss_get_env_as("cog-shallow-specialize"); @@ -249,7 +251,8 @@ Handle MinerSCM::do_shallow_specialize(Handle pattern, HandleSet shaspes = MinerUtils::shallow_specialize(pattern, db_seq, ms, mv, type_check->getTruthValue()->get_mean() > 0, - glob_support->getTruthValue()->get_mean() > 0); + glob_support->getTruthValue()->get_mean() > 0, + ignore->getOutgoingSet()); return as->add_link(SET_LINK, HandleSeq(shaspes.begin(), shaspes.end())); } diff --git a/opencog/miner/MinerUtils.cc b/opencog/miner/MinerUtils.cc index b3ef73103..883823cb0 100644 --- a/opencog/miner/MinerUtils.cc +++ b/opencog/miner/MinerUtils.cc @@ -56,7 +56,8 @@ namespace opencog HandleSetSeq MinerUtils::shallow_abstract(const Valuations& valuations, unsigned ms, bool type_check, - bool glob_support) + bool glob_support, + const HandleSeq& ignore) { // Base case if (valuations.no_focus()) @@ -66,7 +67,7 @@ HandleSetSeq MinerUtils::shallow_abstract(const Valuations& valuations, HandleSetSeq shabs_per_var{focus_shallow_abstract(valuations, ms, type_check, glob_support)}; valuations.inc_focus_variable(); - HandleSetSeq remaining = shallow_abstract(valuations, ms, type_check, glob_support); + HandleSetSeq remaining = shallow_abstract(valuations, ms, type_check, glob_support, ignore); valuations.dec_focus_variable(); append(shabs_per_var, remaining); return shabs_per_var; @@ -472,10 +473,11 @@ HandleSetSeq MinerUtils::shallow_abstract(const Handle& pattern, const HandleSeq& db, unsigned ms, bool type_check, - bool glob_support) + bool glob_support, + const HandleSeq& ignore) { Valuations valuations(pattern, db); - return shallow_abstract(valuations, ms, type_check, glob_support); + return shallow_abstract(valuations, ms, type_check, glob_support, ignore); } HandleSet MinerUtils::shallow_specialize(const Handle& pattern, @@ -483,11 +485,12 @@ HandleSet MinerUtils::shallow_specialize(const Handle& pattern, unsigned ms, unsigned mv, bool type_check, - bool glob_support) + bool glob_support, + const HandleSeq& ignore) { // Calculate all shallow abstractions of pattern HandleSetSeq shabs_per_var = - shallow_abstract(pattern, db, ms, type_check, glob_support); + shallow_abstract(pattern, db, ms, type_check, glob_support, ignore); // For each variable of pattern, generate the corresponding shallow // specializations diff --git a/opencog/miner/MinerUtils.h b/opencog/miner/MinerUtils.h index d982224de..461727bbc 100644 --- a/opencog/miner/MinerUtils.h +++ b/opencog/miner/MinerUtils.h @@ -78,7 +78,8 @@ class MinerUtils */ static HandleSetSeq shallow_abstract(const Valuations &valuations, unsigned ms, bool type_check, - bool glob_support); + bool glob_support, + const HandleSeq& ignore); /** * Given valuations produce all shallow abstractions reaching @@ -246,7 +247,8 @@ class MinerUtils const HandleSeq& db, unsigned ms, bool type_check, - bool glob_support); + bool glob_support, + const HandleSeq& ignore); /** * Return all shallow specializations of pattern with support ms @@ -260,7 +262,8 @@ class MinerUtils unsigned ms, unsigned mv=UINT_MAX, bool type_check=false, - bool glob_support=false); + bool glob_support=false, + const HandleSeq& ignore={}); /** * Create a pattern body from clauses, introducing an AndLink if From 8f08fa1da16a2b92031eb45ec91982eba6b72fa8 Mon Sep 17 00:00:00 2001 From: Kasim Date: Fri, 11 Dec 2020 15:30:35 +0300 Subject: [PATCH 3/7] Add default ignore parameter --- opencog/miner/miner-utils.scm | 1 + 1 file changed, 1 insertion(+) diff --git a/opencog/miner/miner-utils.scm b/opencog/miner/miner-utils.scm index 305311a84..0d6b4847e 100644 --- a/opencog/miner/miner-utils.scm +++ b/opencog/miner/miner-utils.scm @@ -49,6 +49,7 @@ (define default-db-ratio 1) (define default-type-check #f) (define default-glob-support #f) +(define default-ignore '()) ;; For some crazy reason I need to repaste absolutely-true here while ;; it is already defined in ure. From e0d6decd78721ee7dec5dc28bd81a4de78692e1d Mon Sep 17 00:00:00 2001 From: Kasim Date: Fri, 11 Dec 2020 15:31:59 +0300 Subject: [PATCH 4/7] Ignore focus variable if in ignore set --- opencog/miner/MinerUtils.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/opencog/miner/MinerUtils.cc b/opencog/miner/MinerUtils.cc index 883823cb0..f649dc887 100644 --- a/opencog/miner/MinerUtils.cc +++ b/opencog/miner/MinerUtils.cc @@ -63,6 +63,14 @@ HandleSetSeq MinerUtils::shallow_abstract(const Valuations& valuations, if (valuations.no_focus()) return HandleSetSeq(); + // Dont Specialize Variable if it is in ignore. + if (std::count(ignore.begin(), ignore.end(), valuations.focus_variable())) { + valuations.inc_focus_variable(); + HandleSetSeq shabs_per_var = shallow_abstract(valuations, ms, type_check, glob_support, ignore); + valuations.dec_focus_variable(); + return shabs_per_var; + } + // Recursive case HandleSetSeq shabs_per_var{focus_shallow_abstract(valuations, ms, type_check, glob_support)}; From 69bc04a18d851f1533317f00b324bbbd795288d5 Mon Sep 17 00:00:00 2001 From: Kasim Date: Fri, 11 Dec 2020 15:33:53 +0300 Subject: [PATCH 5/7] Pass empty ignore param --- opencog/miner/Miner.cc | 2 +- opencog/miner/MinerSCM.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/opencog/miner/Miner.cc b/opencog/miner/Miner.cc index 3df4503dd..862602f02 100644 --- a/opencog/miner/Miner.cc +++ b/opencog/miner/Miner.cc @@ -135,7 +135,7 @@ HandleTree Miner::specialize_alt(const Handle& pattern, // Calculate all shallow abstractions of pattern // No type support for cpp-miner. - HandleSetSeq shabs = MinerUtils::shallow_abstract(valuations, param.minsup, false, false); + HandleSetSeq shabs = MinerUtils::shallow_abstract(valuations, param.minsup, false, false, {}); // Generate all associated specializations for (unsigned i = 0; i < shabs.size(); i++) { diff --git a/opencog/miner/MinerSCM.cc b/opencog/miner/MinerSCM.cc index 95bf0db7c..0eea1aeff 100644 --- a/opencog/miner/MinerSCM.cc +++ b/opencog/miner/MinerSCM.cc @@ -208,7 +208,7 @@ Handle MinerSCM::do_shallow_abstract(Handle pattern, // Generate all shallow abstractions HandleSetSeq shabs_per_var = // TODO add type and glob params. - MinerUtils::shallow_abstract(pattern, db_seq, ms, false, false); + MinerUtils::shallow_abstract(pattern, db_seq, ms, false, false, {}); // Turn that sequence of handle sets into a set of ready to be // applied shallow abstractions From 8fd14b0a0b0935277e51df370d6eb00bdefdfed9 Mon Sep 17 00:00:00 2001 From: Kasim Date: Fri, 11 Dec 2020 15:37:12 +0300 Subject: [PATCH 6/7] Support ignore parm in UTest utils --- tests/miner/MinerUTest.cxxtest | 18 ++++++++++++------ tests/miner/MinerUTestUtils.cc | 25 ++++++++++++++++++++----- tests/miner/MinerUTestUtils.h | 9 ++++++--- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/tests/miner/MinerUTest.cxxtest b/tests/miner/MinerUTest.cxxtest index 01f33b1cf..e8769afe3 100644 --- a/tests/miner/MinerUTest.cxxtest +++ b/tests/miner/MinerUTest.cxxtest @@ -121,7 +121,8 @@ private: bool enforce_specialization=true, double complexity_penalty=0.0, bool type_check=false, - bool glob_support=false); + bool glob_support=false, + std::vector ignore_set={}); Handle ure_pm(const HandleSeq& db, int minsup, int max_iter=-1, Handle initpat=Handle::UNDEFINED, bool conjunction_expansion=false, @@ -132,7 +133,8 @@ private: bool enforce_specialization=true, double complexity_penalty=0.0, bool type_check=false, - bool glob_support=false); + bool glob_support=false, + std::vector ignore_set={}); /** * Configure the C++ Miner and run it. @@ -250,7 +252,8 @@ Handle MinerUTest::ure_pm(const AtomSpace& db_as, int minsup, bool enforce_specialization, double complexity_penalty, bool type_check, - bool glob_support) + bool glob_support, + vector ignore_set) { return MinerUTestUtils::ure_pm(_as, _scm, pm_rb, db_as, minsup, maximum_iterations, initpat, @@ -261,7 +264,8 @@ Handle MinerUTest::ure_pm(const AtomSpace& db_as, int minsup, enforce_specialization, complexity_penalty, type_check, - glob_support); + glob_support, + ignore_set); } Handle MinerUTest::ure_pm(const HandleSeq& db, int minsup, @@ -274,7 +278,8 @@ Handle MinerUTest::ure_pm(const HandleSeq& db, int minsup, bool enforce_specialization, double complexity_penalty, bool type_check, - bool glob_support) + bool glob_support, + vector ignore_set) { return MinerUTestUtils::ure_pm(_as, _scm, pm_rb, db, minsup, maximum_iterations, initpat, @@ -285,7 +290,8 @@ Handle MinerUTest::ure_pm(const HandleSeq& db, int minsup, enforce_specialization, complexity_penalty, type_check, - glob_support); + glob_support, + ignore_set); } HandleTree MinerUTest::cpp_pm(const AtomSpace& db_as, diff --git a/tests/miner/MinerUTestUtils.cc b/tests/miner/MinerUTestUtils.cc index 9a3082dfc..49ec9f09b 100644 --- a/tests/miner/MinerUTestUtils.cc +++ b/tests/miner/MinerUTestUtils.cc @@ -159,7 +159,8 @@ Handle MinerUTestUtils::ure_pm(AtomSpace& as, bool enforce_specialization, double complexity_penalty, bool type_check, - bool glob_support) + bool glob_support, + std::vector ignore_set) { HandleSeq db; db_as.get_handles_by_type(std::inserter(db, db.end()), @@ -168,7 +169,7 @@ Handle MinerUTestUtils::ure_pm(AtomSpace& as, conjunction_expansion, max_conjuncts, max_variables, max_spcial_conjuncts, max_cnjexp_variables, enforce_specialization, complexity_penalty, - type_check, glob_support); + type_check, glob_support, ignore_set); } Handle MinerUTestUtils::ure_pm(AtomSpace& as, @@ -186,7 +187,8 @@ Handle MinerUTestUtils::ure_pm(AtomSpace& as, bool enforce_specialization, double complexity_penalty, bool type_check, - bool glob_support) + bool glob_support, + std::vector ignore_set) { // Make (Member dt (Concept "db)) links for (const Handle& dt : db) @@ -216,7 +218,8 @@ Handle MinerUTestUtils::ure_pm(AtomSpace& as, max_cnjexp_variables, enforce_specialization, type_check, - glob_support); + glob_support, + ignore_set); // Otherwise prepare the source TruthValuePtr tv = TruthValue::TRUE_TV(); @@ -317,6 +320,15 @@ void MinerUTestUtils::configure_mandatory_rules(SchemeEval& scm) logger().debug() << "MinerUTest::configure_mandatory_rules() rs = " << rs; } +inline std::string comb_vars(std::vector vnames) +{ + std::string slink = "(SetLink "; + for(auto vn : vnames) + slink += "(VariableNode \"" + vn +"\") "; + slink += ")"; + return slink; +} + void MinerUTestUtils::configure_optional_rules(SchemeEval& scm, bool conjunction_expansion, unsigned max_conjuncts, @@ -325,7 +337,8 @@ void MinerUTestUtils::configure_optional_rules(SchemeEval& scm, unsigned max_cnjexp_variables, bool enforce_specialization, bool type_check, - bool glob_support) + bool glob_support, + std::vector ignore_set) { std::string call = "(configure-optional-rules (Concept \"pm-rbs\")"; call += " #:conjunction-expansion #"; @@ -344,6 +357,8 @@ void MinerUTestUtils::configure_optional_rules(SchemeEval& scm, call += type_check ? "#t" : "#f"; call += " #:glob-support "; call += glob_support ? "#t" : "#f"; + call += " #:ignore "; + call += comb_vars(ignore_set); call += ")"; std::string rs = scm.eval(call); logger().debug() << "MinerUTest::configure_optional_rules() rs = " << rs; diff --git a/tests/miner/MinerUTestUtils.h b/tests/miner/MinerUTestUtils.h index a6a35c051..0c0d011ea 100644 --- a/tests/miner/MinerUTestUtils.h +++ b/tests/miner/MinerUTestUtils.h @@ -186,7 +186,8 @@ class MinerUTestUtils bool enforce_specialization=true, double complexity_penalty=0.0, bool type_check=false, - bool glob_support=false); + bool glob_support=false, + std::vector ignore_set= {}); static Handle ure_pm(AtomSpace& as, SchemeEval& scm, const Handle& pm_rb, @@ -201,7 +202,8 @@ class MinerUTestUtils bool enforce_specialization=true, double complexity_penalty=0.0, bool type_check=false, - bool glob_support=false); + bool glob_support=false, + std::vector ignore_set= {}); /** * Configure the C++ Miner and run it. @@ -291,7 +293,8 @@ class MinerUTestUtils unsigned max_cnjexp_variables=UINT_MAX, bool enforce_specialization=false, bool type_check=false, - bool glob_support=false); + bool glob_support=false, + std::vector ignore_set= {}); static void configure_surprisingness(SchemeEval& scm, const Handle& surp_rb, const std::string& mode, From 5ba0b80d8dba2d48a82d019b1784bc3b7809e0f6 Mon Sep 17 00:00:00 2001 From: Kasim Date: Fri, 11 Dec 2020 15:37:53 +0300 Subject: [PATCH 7/7] Test ignore var --- tests/miner/MinerUTest.cxxtest | 38 +++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/tests/miner/MinerUTest.cxxtest b/tests/miner/MinerUTest.cxxtest index e8769afe3..a1d605b12 100644 --- a/tests/miner/MinerUTest.cxxtest +++ b/tests/miner/MinerUTest.cxxtest @@ -202,6 +202,7 @@ public: void test_type_support_1(); void test_type_support_2(); void test_typed_glob(); + void test_ignore_var(); void test_2conjuncts_1(); void test_2conjuncts_2(); void test_2conjuncts_3(); @@ -900,7 +901,7 @@ void MinerUTest::test_shallow_abstract() int ms = 5; // Calculate the shallow abstractions - HandleSetSeq result = MinerUtils::shallow_abstract(pattern, db, ms, false, false); + HandleSetSeq result = MinerUtils::shallow_abstract(pattern, db, ms, false, false, {}); // Construct expected shallow abstractions Handle @@ -1647,6 +1648,41 @@ void MinerUTest::test_typed_glob() TS_ASSERT(are_in(ure_expected->getOutgoingSet(), ure_results->getOutgoingSet())); } +void MinerUTest::test_ignore_var() +{ + logger().info("BEGIN TEST: %s", __FUNCTION__); + + // Define db + Handle InhAB = al(INHERITANCE_LINK, A, B), + InhAC = al(INHERITANCE_LINK, A, C), + InhBC = al(INHERITANCE_LINK, B, C); + HandleSeq db{A, B, C, InhAB, InhAC, InhBC}; + + // Define pattern parts + Handle VarXY = al(VARIABLE_SET, X, Y), + InhXY = al(INHERITANCE_LINK, X, Y), + InhAY = al(INHERITANCE_LINK, A, Y); + + // Define initpat + Handle initpat = MinerUtils::mk_pattern_no_vardecl({InhXY}); + + // Ignore vars +// Handle ignore_set = createLink(SET_LINK, Y); + vector ignore_set = {"$Y"}; + + // Run URE pattern miner + Handle ure_results = ure_pm(db, 2, 10, initpat, + false, UINT_MAX, UINT_MAX, 1, UINT_MAX, true, 0.0, false, false, ignore_set), + ure_expected = mk_minsup_evals(2, + {MinerUtils::mk_pattern(VarXY, {InhXY}), + MinerUtils::mk_pattern(Y, {InhAY}) }); + + logger().debug() << "ure_results = " << oc_to_string(ure_results); + logger().debug() << "ure_expected = " << oc_to_string(ure_expected); + + TS_ASSERT(content_eq(ure_results, ure_expected)); +} + void MinerUTest::test_2conjuncts_1() { logger().info("BEGIN TEST: %s", __FUNCTION__);