diff --git a/cmake/version.cmake b/cmake/version.cmake index 996fad0e13..c8d05f5baa 100755 --- a/cmake/version.cmake +++ b/cmake/version.cmake @@ -1,7 +1,7 @@ set(CADABRA_VERSION_MAJOR 2) set(CADABRA_VERSION_MINOR 4) set(CADABRA_VERSION_PATCH 5) -set(CADABRA_VERSION_TWEAK 0) +set(CADABRA_VERSION_TWEAK 1) set(COPYRIGHT_YEARS "2001-2023") math(EXPR SYSTEM_BITS "${CMAKE_SIZEOF_VOID_P} * 8") find_program(GIT git PATHS ${GIT_DIR}) diff --git a/core/Compare.cc b/core/Compare.cc index 0c2b8cca11..200e9f1456 100644 --- a/core/Compare.cc +++ b/core/Compare.cc @@ -17,13 +17,14 @@ #include "properties/Integer.hh" #include "properties/SortOrder.hh" -//#define DEBUG 1 +// #define DEBUG 1 +static bool debug_stop = false; #ifdef DEBUG - #define DEBUGLN(ln) ln +#define DEBUGLN(ln) if(!debug_stop) { ln; } #else - #define DEBUGLN(ln) +#define DEBUGLN(ln) #endif namespace cadabra { @@ -452,7 +453,7 @@ namespace cadabra { return r; #endif - std::cerr << tab() << "result = "; + DEBUGLN( std::cerr << tab() << "result = "; ); switch(r) { case match_t::node_match: std::cerr << "node_match"; @@ -507,6 +508,7 @@ namespace cadabra { bool is_sibling_pattern=false; bool is_coordinate=false; bool is_number=false; + bool two_is_value=false; if(one->fl.bracket==str_node::b_none && one->is_index() ) is_index=true; @@ -517,7 +519,8 @@ namespace cadabra { else if(one->is_siblings_wildcard()) is_sibling_pattern=true; else if(is_index && one->is_integer()==false) { - // Things in _{..} or ^{..} are either indices (implicit patterns) or coordinates. + // Things in _{..} or ^{..} are either indices (implicit patterns), or coordinates (as + // numbers are treated in the last branch below). const Coordinate *cdn1=0; if(use_props==useprops_t::always) { DEBUGLN( std::cerr << tab() << "is " << *one->name << " a coordinate?" << std::endl; ); @@ -548,7 +551,7 @@ namespace cadabra { if(two->is_rational() && implicit_pattern) { // Determine whether 'one' can take the value 'two'. - //std::cerr << "**** can one take value two " << use_props << std::endl; + DEBUGLN( std::cerr << tab() << "can one take value two (use props = " << use_props << ")" << std::endl; ); const Integer *ip = 0; if(use_props==useprops_t::always) { DEBUGLN( std::cerr << tab() << "is " << *one->name << " an integer?" << std::endl; ); @@ -557,6 +560,8 @@ namespace cadabra { } if(ip==0) return report(match_t::no_match_less); + + DEBUGLN( std::cerr << tab() << "yes, potentially, check the range" << std::endl; ); bool lower_bdy=true, upper_bdy=true; multiplier_t from, to; @@ -573,7 +578,7 @@ namespace cadabra { if((lower_bdy && *two->multiplier < from) || (upper_bdy && *two->multiplier > to)) return report(match_t::no_match_less); - // std::cerr << tab() << Ex(one) << tab() << "can take value " << *two->multiplier << std::endl; + DEBUGLN( std::cerr << tab() << Ex(one) << tab() << "can take value " << *two->multiplier << std::endl ); } // We want to search the replacement map for replacement rules which we have @@ -642,11 +647,13 @@ namespace cadabra { const Indices *t1=0; const Indices *t2=0; if(use_props==useprops_t::always) { - DEBUGLN( std::cerr << tab() << "is " << one << " an index?" << std::endl; ); + DEBUGLN( std::cerr << tab() << "is " << *one->name << " an index?" << std::endl; ); + debug_stop=true; t1=properties.get(one, false); + debug_stop=false; DEBUGLN( std::cerr << tab() << "found for one: " << t1 << std::endl; ); if(two->is_rational()==false) { - DEBUGLN( std::cerr << tab() << "is " << two << " an index?" << std::endl; ); + DEBUGLN( std::cerr << tab() << "is " << *two->name << " an index?" << std::endl; ); t2=properties.get(two, false); DEBUGLN( std::cerr << tab() << t2 << std::endl; ); // It is still possible that t2 is a Coordinate and @@ -665,8 +672,10 @@ namespace cadabra { if(subtree_compare(&properties, a.begin(), two, 0)==0) return true; else return false; }); - if(ivals!=t1->values.end()) + if(ivals!=t1->values.end()) { t2=t1; + two_is_value=true; + } } } else { @@ -769,10 +778,18 @@ namespace cadabra { // they matched because they are from the same set but do not have the same // name, we still need to let the caller know about this. if(is_index) { - int xc = subtree_compare(0, one, two, ignore_parent_rel?(-1):(-2)); - if(xc==0) return report(match_t::subtree_match); - if(xc>0) return report(match_t::match_index_less); - return report(match_t::match_index_greater); + if(two->is_rational() || two_is_value) { + // We matched an index in 'one' to a value in 'two', report as matching. + DEBUGLN( std::cerr << "Matched index to numerical value." << std::endl; ); + return report(match_t::subtree_match); + } + else { + DEBUGLN( std::cerr << "Index type matches, report whether names match too." << std::endl; ); + int xc = subtree_compare(0, one, two, ignore_parent_rel?(-1):(-2)); + if(xc==0) return report(match_t::subtree_match); + if(xc>0) return report(match_t::match_index_less); + return report(match_t::match_index_greater); + } } else return report(match_t::node_match); } diff --git a/core/ExNode.cc b/core/ExNode.cc index 346a868dd1..1599fd4261 100644 --- a/core/ExNode.cc +++ b/core/ExNode.cc @@ -499,8 +499,8 @@ bool Ex_matches(std::shared_ptr ex, ExNode& other) { Ex_comparator comp(get_kernel_from_scope()->properties); auto ret=comp.equal_subtree(ex->begin(), other.it); - if(ret==Ex_comparator::match_t::no_match_less || ret==Ex_comparator::match_t::no_match_greater) return false; - return true; + if(ret==Ex_comparator::match_t::node_match || ret==Ex_comparator::match_t::subtree_match) return true; + return false; } bool Ex_matches_Ex(std::shared_ptr ex, std::shared_ptr other) @@ -510,8 +510,8 @@ bool Ex_matches_Ex(std::shared_ptr ex, std::shared_ptr other) if(ex->begin()==ex->end() || other->begin()==other->end()) return false; auto ret=comp.equal_subtree(ex->begin(), other->begin()); - if(ret==Ex_comparator::match_t::no_match_less || ret==Ex_comparator::match_t::no_match_greater) return false; - return true; + if(ret==Ex_comparator::match_t::node_match || ret==Ex_comparator::match_t::subtree_match) return true; + return false; } bool ExNode_less(ExNode& one, ExNode& two) diff --git a/tests/programming.cdb b/tests/programming.cdb index 42a6cd5009..3bb3a121da 100644 --- a/tests/programming.cdb +++ b/tests/programming.cdb @@ -272,6 +272,7 @@ test12() def test13(): __cdbkernel__ = create_scope() {m,n}::Indices(values={a,b}); + {\mu,\nu}::Integer. {\mu,\nu}::Indices(values={0,1,2,3}); assert( $A_{m n}$.matches($A_{a b}$) == True ) assert( $A_{m n}$.matches($A_{a a}$) == True ) @@ -322,3 +323,12 @@ def test15(): test15() +def test16(): + # There are many ways in which a match can fail... + __cdbkernel__ = create_scope() + {a,b,c}::Indices(vector, position=independent). + {i,j,k}::Indices(isospin, position=independent). + assert($\Lambda_{a}$.matches($\Lambda_{i}$)==False) + assert($\Lambda_{a}$.matches($\Lambda^{i}$)==False) + +test16() diff --git a/tests/substitute.cdb b/tests/substitute.cdb index 36e450959b..d7ae4da695 100644 --- a/tests/substitute.cdb +++ b/tests/substitute.cdb @@ -542,4 +542,19 @@ def test126(): test126() +def test127(): + # Expect an exception when substituting with empty rule. + __cdbkernel__=create_scope() + ex:= A + B; + try: + substitute(ex, $ $); + assert(False) + except Exception: + print("Test 127a passed") + try: + substitute(ex, ${ }$) + assert(1==0) + except Exception: + print("Test 127b passed") +test127()