- pointer_to_map_function_1arg<const ex &> fcn(get_clifford_comp, c);
- int ival = ex_to<numeric>(ex_to<varidx>(c.op(1)).get_value()).to_int();
-
- if (is_a<add>(e) || is_a<lst>(e) // || is_a<pseries>(e) || is_a<integral>(e)
- || is_a<matrix>(e))
- return e.map(fcn);
- else if (is_a<ncmul>(e) || is_a<mul>(e)) {
- // find a Clifford unit with the same metric, delete it and substitute its index
- size_t ind = e.nops() + 1;
- for (size_t j = 0; j < e.nops(); j++)
- if (is_a<clifford>(e.op(j)) && ex_to<clifford>(c).same_metric(e.op(j)))
- if (ind > e.nops())
- ind = j;
- else
- throw(std::invalid_argument("Expression is a Clifford multi-vector"));
- if (ind < e.nops()) {
- ex S = 1;
- bool same_value_index, found_dummy;
- same_value_index = ( ex_to<varidx>(e.op(ind).op(1)).is_numeric()
- && (ival == ex_to<numeric>(ex_to<varidx>(e.op(ind).op(1)).get_value()).to_int()) );
- found_dummy = same_value_index;
- for(size_t j=0; j < e.nops(); j++)
- if (j != ind)
- if (same_value_index)
- S = S * e.op(j);
- else {
- exvector ind_vec = ex_to<indexed>(e.op(j)).get_dummy_indices(ex_to<indexed>(e.op(ind)));
- if (ind_vec.size() > 0) {
- found_dummy = true;
- exvector::const_iterator it = ind_vec.begin(), itend = ind_vec.end();
- while (it != itend) {
- S = S * e.op(j).subs(lst(ex_to<varidx>(*it) == ival, ex_to<varidx>(*it).toggle_variance() == ival), subs_options::no_pattern);
- ++it;
- }
- } else
- S = S * e.op(j);
- }
- return (found_dummy ? S : 0);
- } else
- throw(std::invalid_argument("Expression is not a Clifford vector to the given units"));
- } else if (e.is_zero())
- return e;
- else if (is_a<clifford>(e) && ex_to<clifford>(e).same_metric(c))
- if ( ex_to<varidx>(e.op(1)).is_numeric() &&
- (ival != ex_to<numeric>(ex_to<varidx>(e.op(1)).get_value()).to_int()) )
+ // make expansion on the top-level call only
+ ex e1=(root? e.expand() : e);
+
+ pointer_to_map_function_2args<const ex &, bool> fcn(get_clifford_comp, c, false);
+ int ival = ex_to<numeric>(ex_to<idx>(c.op(1)).get_value()).to_int();
+ int rl=ex_to<clifford>(c).get_representation_label();
+
+ if ( (is_a<add>(e1) || e1.info(info_flags::list) || is_a<matrix>(e1))) {
+ return e1.map(fcn);
+ } else if (is_a<ncmul>(e1) || is_a<mul>(e1)) {
+ // searches are done within products only
+ exvector ev, all_dummy=get_all_dummy_indices(e1);
+ bool found=false, same_value_found=false;
+ ex dummy_ind=0;
+ ev.reserve(e1.nops());
+ for (int i=0; i < e1.nops();++i) {
+ // look for a Clifford unit with the same metric and representation label,
+ // if found remember its index
+ if (is_a<clifford>(e1.op(i)) && ex_to<clifford>(e1.op(i)).get_representation_label() == rl
+ && is_a<cliffordunit>(e1.op(i).op(0)) && ex_to<clifford>(e1.op(i)).same_metric(c)) { // same Clifford unit
+ if (found)
+ throw(std::invalid_argument("get_clifford_comp(): expression is a Clifford multi-vector"));
+ found=true;
+ if (ex_to<idx>(e1.op(i).op(1)).is_numeric() &&
+ (ival == ex_to<numeric>(ex_to<idx>(e1.op(i).op(1)).get_value()).to_int())) {
+ same_value_found = true; // desired index value is found
+ } else if ((std::find(all_dummy.begin(), all_dummy.end(), e1.op(i).op(1)) != all_dummy.end())
+ || (is_a<varidx>(e1.op(i).op(1))
+ && std::find(all_dummy.begin(), all_dummy.end(),
+ ex_to<varidx>(e1.op(i).op(1)).toggle_variance()) != all_dummy.end())) {
+ dummy_ind=(e1.op(i).op(1)); // suitable dummy index found
+ } else
+ ev.push_back(e.op(i)); // another index value
+ } else
+ ev.push_back(e1.op(i));
+ }
+
+ if (! found) // no Clifford units found at all
+ throw(std::invalid_argument("get_clifford_comp(): expression is not a Clifford vector to the given units"));
+
+ ex res=dynallocate<ncmul>(std::move(ev));
+ if (same_value_found) {
+ return res;
+ } else if (! dummy_ind.is_zero()) { // a dummy index was found
+ if (is_a<varidx>(dummy_ind))
+ dummy_ind = ex_to<varidx>(dummy_ind).toggle_variance();
+ return res.subs(dummy_ind==ival, subs_options::no_pattern);
+ } else // found a Clifford unit with another index