+ 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));
+ varidx mu = ex_to<varidx>(c.op(1));
+ if (! mu.is_dim_numeric())
+ throw(std::invalid_argument("clifford_to_lst(): index should have a numeric dimension"));
+ unsigned int D = ex_to<numeric>(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()
+ or (not is_a<numeric>(pow(c.subs(mu == i, subs_options::no_pattern), 2))))
+ algebraic = false;
+ lst V;
+ if (algebraic) {
+ for (unsigned int i = 0; i < D; i++)
+ V.append(remove_dirac_ONE(
+ simplify_indexed(canonicalize_clifford(e * c.subs(mu == i, subs_options::no_pattern) + c.subs(mu == i, subs_options::no_pattern) * e))
+ / (2*pow(c.subs(mu == i, subs_options::no_pattern), 2))));
+ } else {
+ ex e1 = canonicalize_clifford(e);
+ 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(e1, true));
+ 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, bool anticommuting)
+{
+ ex x, D, cu;
+
+ if (! is_a<matrix>(v) && ! is_a<lst>(v))
+ 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<varidx>(G.op(1)).get_dim();
+ else if (is_a<matrix>(G))
+ D = ex_to<matrix>(G).rows();
+ else throw(std::invalid_argument("clifford_moebius_map(): metric should be an indexed object, matrix, or a Clifford unit"));
+
+ varidx mu((new symbol)->setflag(status_flags::dynallocated), D);
+ cu = clifford_unit(mu, G, rl, anticommuting);
+ }
+
+ x = lst_to_clifford(v, cu);
+ ex e = simplify_indexed(canonicalize_clifford((a * x + b) * clifford_inverse(c * x + d)));
+ return clifford_to_lst(e, cu, false);
+}