+ return aux.subs(srl, subs_options::no_pattern).simplify_indexed();
+ }
+}
+
+ex clifford_prime(const ex & e)
+{
+ pointer_to_map_function fcn(clifford_prime);
+ if (is_a<clifford>(e) && is_a<cliffordunit>(e.op(0))) {
+ return -e;
+ } else if (is_a<add>(e) || is_a<ncmul>(e) || is_a<mul>(e) //|| is_a<pseries>(e) || is_a<integral>(e)
+ || is_a<matrix>(e) || is_a<lst>(e)) {
+ return e.map(fcn);
+ } else if (is_a<power>(e)) {
+ return pow(clifford_prime(e.op(0)), e.op(1));
+ } else
+ return e;
+}
+
+ex remove_dirac_ONE(const ex & e, unsigned char rl)
+{
+ pointer_to_map_function_1arg<unsigned char> fcn(remove_dirac_ONE, rl);
+ if (is_a<clifford>(e) && ex_to<clifford>(e).get_representation_label() >= rl) {
+ if (is_a<diracone>(e.op(0)))
+ return 1;
+ else
+ throw(std::invalid_argument("Expression is a non-scalar Clifford number!"));
+ } else if (is_a<add>(e) || is_a<ncmul>(e) || is_a<mul>(e) // || is_a<pseries>(e) || is_a<integral>(e)
+ || is_a<matrix>(e) || is_a<lst>(e)) {
+ return e.map(fcn);
+ } else if (is_a<power>(e)) {
+ return pow(remove_dirac_ONE(e.op(0)), e.op(1));
+ } else
+ return e;
+}
+
+ex clifford_norm(const ex & e)
+{
+ return sqrt(remove_dirac_ONE(canonicalize_clifford(e * clifford_bar(e)).simplify_indexed()));
+}
+
+ex clifford_inverse(const ex & e)
+{
+ ex norm = clifford_norm(e);
+ if (!norm.is_zero())
+ return clifford_bar(e) / pow(norm, 2);
+ else
+ throw(std::invalid_argument("Cannot find inverse of Clifford number with zero norm!"));
+}
+
+ex lst_to_clifford(const ex & v, const ex & mu, const ex & metr, unsigned char rl)
+{
+ if (!ex_to<idx>(mu).is_dim_numeric())
+ throw(std::invalid_argument("Index should have a numeric dimension"));
+ ex e = clifford_unit(mu, metr, rl);
+ return lst_to_clifford(v, e);
+}
+
+ex lst_to_clifford(const ex & v, const ex & e) {
+ unsigned min, max;
+
+ if (is_a<clifford>(e)) {
+ varidx mu = ex_to<varidx>(e.op(1));
+ unsigned dim = (ex_to<numeric>(mu.get_dim())).to_int();
+
+ if (is_a<matrix>(v)) {
+ if (ex_to<matrix>(v).cols() > ex_to<matrix>(v).rows()) {
+ min = ex_to<matrix>(v).rows();
+ max = ex_to<matrix>(v).cols();
+ } else {
+ min = ex_to<matrix>(v).cols();
+ max = ex_to<matrix>(v).rows();
+ }
+ if (min == 1) {
+ if (dim == max)
+ return indexed(v, ex_to<varidx>(mu).toggle_variance()) * e;
+ else
+ throw(std::invalid_argument("Dimensions of vector and clifford unit mismatch"));
+ } else
+ throw(std::invalid_argument("First argument should be a vector vector"));
+ } else if (is_a<lst>(v)) {
+ if (dim == ex_to<lst>(v).nops())
+ return indexed(matrix(dim, 1, ex_to<lst>(v)), ex_to<varidx>(mu).toggle_variance()) * e;
+ else
+ throw(std::invalid_argument("List length and dimension of clifford unit mismatch"));
+ } else
+ throw(std::invalid_argument("Cannot construct from anything but list or vector"));
+ } else
+ throw(std::invalid_argument("The second argument should be a Clifford unit"));
+}
+
+/** Auxiliary structure to define a function for striping one Clifford unit
+ * from vectors. Used in clifford_to_lst(). */
+static ex get_clifford_comp(const ex & e, const ex & c)
+{
+ 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()) )
+ return 0;
+ else
+ return 1;
+ else
+ throw(std::invalid_argument("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("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), 2).is_zero()
+ or (not is_a<numeric>(pow(c.subs(mu == i), 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) + c.subs(mu == i) * e))
+ / (2*pow(c.subs(mu == i), 2))));
+ else {
+ ex e1 = canonicalize_clifford(e);
+ for (unsigned int i = 0; i < D; i++)
+ V.append(get_clifford_comp(e1, c.subs(c.op(1) == i)));