+ if (ind < e.nops()) {
+ ex S = 1;
+ bool same_value_index, found_dummy;
+ same_value_index = ( ex_to<idx>(e.op(ind).op(1)).is_numeric()
+ && (ival == ex_to<numeric>(ex_to<idx>(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) {
+ ex curridx = *it;
+ ex curridx_toggle = is_a<varidx>(curridx)
+ ? ex_to<varidx>(curridx).toggle_variance()
+ : curridx;
+ S = S * e.op(j).subs(lst(curridx == ival,
+ curridx_toggle == ival), subs_options::no_pattern);
+ ++it;
+ }
+ } else
+ S = S * e.op(j);
+ }
+ }
+ }
+ return (found_dummy ? S : 0);
+ } else
+ throw(std::invalid_argument("get_clifford_comp(): 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<idx>(e.op(1)).is_numeric() &&
+ (ival != ex_to<numeric>(ex_to<idx>(e.op(1)).get_value()).to_int()) )
+ return 0;
+ else
+ return 1;
+ else
+ throw(std::invalid_argument("get_clifford_comp(): expression is not usable as a Clifford vector"));
+}
+
+
+lst clifford_to_lst(const ex & e, const ex & c, bool algebraic)
+{
+ GINAC_ASSERT(is_a<clifford>(c));
+ ex mu = c.op(1);
+ if (! ex_to<idx>(mu).is_dim_numeric())
+ throw(std::invalid_argument("clifford_to_lst(): index should have a numeric dimension"));
+ unsigned int D = ex_to<numeric>(ex_to<idx>(mu).get_dim()).to_int();
+
+ if (algebraic) // check if algebraic method is applicable
+ for (unsigned int i = 0; i < D; i++)
+ if (pow(c.subs(mu == i, subs_options::no_pattern), 2).is_zero()
+ || (! is_a<numeric>(pow(c.subs(mu == i, subs_options::no_pattern), 2))))
+ algebraic = false;
+ lst V;
+ ex v0 = remove_dirac_ONE(canonicalize_clifford(e+clifford_prime(e)).normal())/2;
+ if (! v0.is_zero())
+ V.append(v0);
+ ex e1 = canonicalize_clifford(e - v0 * dirac_ONE(ex_to<clifford>(c).get_representation_label()));
+ if (algebraic) {
+ for (unsigned int i = 0; i < D; i++)
+ V.append(remove_dirac_ONE(
+ simplify_indexed(canonicalize_clifford(e1 * c.subs(mu == i, subs_options::no_pattern) + c.subs(mu == i, subs_options::no_pattern) * e1))
+ / (2*pow(c.subs(mu == i, subs_options::no_pattern), 2))));
+ } else {
+ try {
+ for (unsigned int i = 0; i < D; i++)
+ V.append(get_clifford_comp(e1, c.subs(c.op(1) == i, subs_options::no_pattern)));
+ } catch (std::exception &p) {
+ /* Try to expand dummy summations to simplify the expression*/
+ e1 = canonicalize_clifford(expand_dummy_sum(e, true));
+ V.remove_all();
+ v0 = remove_dirac_ONE(canonicalize_clifford(e1+clifford_prime(e1)).normal())/2;
+ if (! v0.is_zero()) {
+ V.append(v0);
+ e1 = canonicalize_clifford(e1 - v0 * dirac_ONE(ex_to<clifford>(c).get_representation_label()));
+ }
+ for (unsigned int i = 0; i < D; i++)
+ V.append(get_clifford_comp(e1, c.subs(c.op(1) == i, subs_options::no_pattern)));
+ }
+ }
+ return V;
+}
+
+
+ex clifford_moebius_map(const ex & a, const ex & b, const ex & c, const ex & d, const ex & v, const ex & G, unsigned char rl)
+{
+ ex x, D, cu;
+
+ if (! is_a<matrix>(v) && ! v.info(info_flags::list))
+ throw(std::invalid_argument("clifford_moebius_map(): parameter v should be either vector or list"));
+
+ if (is_a<clifford>(G)) {
+ cu = G;
+ } else {
+ if (is_a<indexed>(G)) {
+ D = ex_to<idx>(G.op(1)).get_dim();
+ varidx mu((new symbol)->setflag(status_flags::dynallocated), D);
+ cu = clifford_unit(mu, G, rl);
+ } else if (is_a<matrix>(G)) {
+ D = ex_to<matrix>(G).rows();
+ idx mu((new symbol)->setflag(status_flags::dynallocated), D);
+ cu = clifford_unit(mu, G, rl);
+ } else throw(std::invalid_argument("clifford_moebius_map(): metric should be an indexed object, matrix, or a Clifford unit"));
+