@@ -1260,11 +1260,69 @@ int Ex_comparator::can_swap_ilist_ilist(Ex::iterator obj1, Ex::iterator obj2)
12601260 return sign;
12611261 }
12621262
1263+ bool Ex_comparator::can_swap_different_indexsets (Ex::iterator obj1, Ex::iterator obj2)
1264+ {
1265+ std::set<const Indices *> index_sets1;
1266+ // std::cerr << "Are " << obj1 << " and " << obj2 << " swappable?" << std::endl;
1267+
1268+ index_iterator it1=index_iterator::begin (properties, obj1);
1269+ while (it1!=index_iterator::end (properties, obj1)) {
1270+ auto ind = properties.get <Indices>(it1, true );
1271+ if (!ind) return false ;
1272+ index_sets1.insert (ind);
1273+ ++it1;
1274+ }
1275+ index_iterator it2=index_iterator::begin (properties, obj2);
1276+ while (it2!=index_iterator::end (properties, obj2)) {
1277+ auto ind = properties.get <Indices>(it2, true );
1278+ if (!ind) return false ;
1279+ if (index_sets1.find (ind)!=index_sets1.end ()) {
1280+ // std::cerr << "NO" << std::endl;
1281+ return false ;
1282+ }
1283+ ++it2;
1284+ }
1285+ // std::cerr << "YES" << std::endl;
1286+ return true ;
1287+ }
1288+
12631289int Ex_comparator::can_swap (Ex::iterator one, Ex::iterator two, match_t subtree_comparison,
1264- bool ignore_implicit_indices)
1290+ bool ignore_implicit_indices)
12651291 {
12661292 // std::cerr << "can_swap " << *one->name << " " << *two->name << " " << ignore_implicit_indices << std::endl;
12671293
1294+ // Explicitly declared commutation behaviour goes first.
1295+ const CommutingBehaviour *com = properties.get_composite <CommutingBehaviour>(one, two, true );
1296+ if (com)
1297+ return com->sign ();
1298+
1299+
1300+ // If both objects have implicit indices, we cannot swap the
1301+ // objects because that would re-order the index line. The sole
1302+ // exception is when these indices are explicitly stated to be in
1303+ // different sets.
1304+
1305+ const ImplicitIndex *ii1 = properties.get_composite <ImplicitIndex>(one);
1306+ const ImplicitIndex *ii2 = properties.get_composite <ImplicitIndex>(two);
1307+ if (!ignore_implicit_indices) {
1308+ if (ii1) {
1309+ if (ii1->explicit_form .size ()==0 ) {
1310+ if (ii2) return 0 ; // nothing known about explicit form
1311+ }
1312+ else one=ii1->explicit_form .begin ();
1313+ }
1314+ if (ii2) {
1315+ if (ii2->explicit_form .size ()==0 ) {
1316+ if (ii1) return 0 ; // nothing known about explicit form
1317+ }
1318+ else two=ii2->explicit_form .begin ();
1319+ }
1320+ // Check that indices in one and two are in mutually exclusive sets.
1321+ if (ii1 && ii2)
1322+ if (!can_swap_different_indexsets (one, two))
1323+ return false ;
1324+ }
1325+
12681326 // Differential forms in a product cannot be moved through each
12691327 // other except when the degree of one of them is zero. In a wedge
12701328 // product, we can move them and potentially pick up a sign.
@@ -1287,43 +1345,6 @@ int Ex_comparator::can_swap(Ex::iterator one, Ex::iterator two, match_t subtree_
12871345 }
12881346 }
12891347 }
1290-
1291- const ImplicitIndex *ii1 = properties.get_composite <ImplicitIndex>(one);
1292- const ImplicitIndex *ii2 = properties.get_composite <ImplicitIndex>(two);
1293-
1294- // When both objects carry an implicit index but the index lines are not connected,
1295- // we should not be using explicit commutation rules, as this would mess up the
1296- // index lines and make the expression meaningless.
1297- // FIXME: this would ideally make use of index and conjugate index lines.
1298-
1299- const DiracBar *db2 = properties.get_composite <DiracBar>(two);
1300- if (! (ii1 && ii2 && db2) ) {
1301-
1302- // First of all, check whether there is an explicit declaration for the commutativity
1303- // of these two symbols.
1304- // std::cout << *one->name << " explicit " << *two->name << std::endl;
1305- const CommutingBehaviour *com = properties.get_composite <CommutingBehaviour>(one, two, true );
1306-
1307- if (com) {
1308- // std::cout << typeid(com).name() << std::endl;
1309- // std::cout << "explicit " << com->sign() << std::endl;
1310- return com->sign ();
1311- }
1312- }
1313-
1314- if (ignore_implicit_indices==false ) {
1315- // Two implicit-index objects cannot move through each other if they have the
1316- // same type of implicit index.
1317- // std::cout << "can_swap " << *one->name << " " << *two->name << std::endl;
1318-
1319- if (ii1 && ii2) {
1320- if (ii1->set_names .size ()==0 && ii2->set_names .size ()==0 ) return 0 ; // empty index name
1321- for (size_t n1=0 ; n1<ii1->set_names .size (); ++n1)
1322- for (size_t n2=0 ; n2<ii2->set_names .size (); ++n2)
1323- if (ii1->set_names [n1]==ii2->set_names [n2])
1324- return 0 ;
1325- }
1326- }
13271348
13281349 // Do we need to use Self* properties?
13291350 const SelfCommutingBehaviour *sc1 =properties.get_composite <SelfCommutingBehaviour>(one, true );
0 commit comments