*it1=numeric(40)/numeric(3);
*it2=_ex1();
} else {
- int sig1, sig2; // unimportant, since symmetric
- ex idx1=permute_free_index_to_front(col1.seq,iv_intersect,false,&sig1);
- ex idx2=permute_free_index_to_front(col2.seq,iv_intersect,false,&sig2);
+ int dummy; // sign unimportant, since symmetric
+ ex idx1=permute_free_index_to_front(col1.seq,iv_intersect,&dummy);
+ ex idx2=permute_free_index_to_front(col2.seq,iv_intersect,&dummy);
*it1=numeric(5)/numeric(3)*color(color_delta8,idx1,idx2);
*it2=_ex1();
}
*it2=_ex1();
} else {
int sig1, sig2;
- ex idx1=permute_free_index_to_front(col1.seq,iv_intersect,true,&sig1);
- ex idx2=permute_free_index_to_front(col2.seq,iv_intersect,true,&sig2);
+ ex idx1=permute_free_index_to_front(col1.seq,iv_intersect,&sig1);
+ ex idx2=permute_free_index_to_front(col2.seq,iv_intersect,&sig2);
*it1=numeric(sig1*sig2*5)/numeric(3)*color(color_delta8,idx1,idx2);
*it2=_ex1();
}
const color & dref=ex_to_color(*it2);
exvector iv_intersect=idx_intersect(dref.seq,iv);
if (iv_intersect.size()==2) {
- int sig; // unimportant, since symmetric
- ex free_idx=permute_free_index_to_front(dref.seq,iv,false,&sig);
+ int dummy; // sign unimportant, since symmetric
+ ex free_idx=permute_free_index_to_front(dref.seq,iv,&dummy);
*it1=color(color_T,free_idx,rl);
*(it1+1)=color(color_ONE,rl);
*it2=numeric(5)/numeric(6);
exvector iv_intersect=idx_intersect(fref.seq,iv);
if (iv_intersect.size()==2) {
int sig;
- ex free_idx=permute_free_index_to_front(fref.seq,iv,true,&sig);
+ ex free_idx=permute_free_index_to_front(fref.seq,iv,&sig);
*it1=color(color_T,free_idx,rl);
*(it1+1)=color(color_ONE,rl);
*it2=numeric(sig*3)/numeric(2)*I;
// public
+/** Construct symbolic color index, using an automatically generated unique name.
+ *
+ * @param cov Index is covariant (contravariant otherwise)
+ * @return newly constructed index */
coloridx::coloridx(bool cov) : idx(cov)
{
debugmsg("coloridx constructor from bool",LOGLEVEL_CONSTRUCT);
tinfo_key=TINFO_coloridx;
}
+/** Construct symbolic color index with specified name.
+ *
+ * @param n Symbolic index name
+ * @param cov Index is covariant (contravariant otherwise)
+ * @return newly constructed index */
coloridx::coloridx(const std::string & n, bool cov) : idx(n,cov)
{
debugmsg("coloridx constructor from string,bool",LOGLEVEL_CONSTRUCT);
tinfo_key=TINFO_coloridx;
}
+/** Construct symbolic color index with specified name.
+ *
+ * @param n Symbolic index name
+ * @param cov Index is covariant (contravariant otherwise)
+ * @return newly constructed index */
coloridx::coloridx(const char * n, bool cov) : idx(n,cov)
{
debugmsg("coloridx constructor from char*,bool",LOGLEVEL_CONSTRUCT);
tinfo_key=TINFO_coloridx;
}
+/** Construct numeric color index with specified value.
+ *
+ * @param v Numeric index value
+ * @param cov Index is covariant (contravariant otherwise)
+ * @return newly constructed index */
coloridx::coloridx(unsigned v, bool cov) : idx(v,cov)
{
debugmsg("coloridx constructor from unsigned,bool",LOGLEVEL_CONSTRUCT);
namespace GiNaC {
#endif // ndef NO_NAMESPACE_GINAC
+/** Class of indices for color algebra (SU(3)) objects, to tell them apart
+ * from other index families like Lorentz indices. */
class coloridx : public idx
{
GINAC_DECLARE_REGISTERED_CLASS(coloridx, idx)
// public
+/** Construct symbolic index, using an automatically generated unique name.
+ *
+ * @param cov Index is covariant (contravariant otherwise)
+ * @return newly constructed index */
idx::idx(bool cov) : inherited(TINFO_idx), symbolic(true), covariant(cov)
{
debugmsg("idx constructor from bool",LOGLEVEL_CONSTRUCT);
name = "index"+ToString(serial);
}
+/** Construct symbolic index with specified name.
+ *
+ * @param n Symbolic index name
+ * @param cov Index is covariant (contravariant otherwise)
+ * @return newly constructed index */
idx::idx(const std::string & n, bool cov) : inherited(TINFO_idx),
symbolic(true), name(n), covariant(cov)
{
serial = next_serial++;
}
+/** Construct symbolic index with specified name.
+ *
+ * @param n Symbolic index name
+ * @param cov Index is covariant (contravariant otherwise)
+ * @return newly constructed index */
idx::idx(const char * n, bool cov) : inherited(TINFO_idx), symbolic(true), name(n), covariant(cov)
{
debugmsg("idx constructor from char*,bool",LOGLEVEL_CONSTRUCT);
serial = next_serial++;
}
+/** Construct numeric index with specified value.
+ *
+ * @param v Numeric index value
+ * @param cov Index is covariant (contravariant otherwise)
+ * @return newly constructed index */
idx::idx(unsigned v, bool cov) : inherited(TINFO_idx), symbolic(false), value(v), covariant(cov)
{
debugmsg("idx constructor from unsigned,bool",LOGLEVEL_CONSTRUCT);
// public
+/** Check whether the index forms a co-/contravariant pair with another
+ * index (i.e. same name/value but opposite co-/contravariance). */
bool idx::is_co_contra_pair(const basic & other) const
{
// like is_equal_same_type(), but tests for different covariant status
return value==o.value;
}
-bool idx::is_symbolic(void) const
-{
- return symbolic;
-}
-
-unsigned idx::get_value(void) const
-{
- return value;
-}
-
-bool idx::is_covariant(void) const
-{
- return covariant;
-}
-
+/** Toggle co-/contravariance of index. */
ex idx::toggle_covariant(void) const
{
idx * i_copy=static_cast<idx *>(duplicate());
// other functions
//////////
+/** Bring a vector of indices into a canonic order. This operation only makes
+ * sense if the object carrying these indices is either symmetric or totally
+ * antisymmetric with respect to the indices.
+ *
+ * @param iv Index vector
+ * @param antisymmetric Whether the object carrying the indices is antisymmetric (symmetric otherwise)
+ * @return the sign introduced by the reordering of the indices. For symmetric
+ * objects this is always +1. For antisymmetric objects this is either
+ * +1 or -1 or 0 (if two equal indices were encountered). If the index
+ * vector was unchanged this function returns INT_MAX. */
int canonicalize_indices(exvector & iv, bool antisymmetric)
{
if (iv.size()<2) {
bool something_changed=false;
int sig=1;
+
// simple bubble sort algorithm should be sufficient for the small number of indices needed
exvector::const_iterator last_idx=iv.end();
exvector::const_iterator next_to_last_idx=iv.end()-1;
}
}
}
+
return something_changed ? sig : INT_MAX;
}
+/** Build a vector of indices as the set intersection of two other index
+ * vectors (i.e. the returned vector contains the indices which appear in
+ * both source vectors). */
exvector idx_intersect(const exvector & iv1, const exvector & iv2)
{
- // build a vector of symbolic indices contained in iv1 and iv2 simultaneously
- // assumes (but does not test) that each index occurs at most twice
+ // Create union vector
+ exvector iv_union;
+ iv_union.reserve(iv1.size() + iv2.size());
+ iv_union.insert(iv_union.end(), iv1.begin(), iv1.end());
+ iv_union.insert(iv_union.end(), iv2.begin(), iv2.end());
+
+ // Sort it
+ canonicalize_indices(iv_union);
+
+ // Look for duplicates
exvector iv_intersect;
- for (exvector::const_iterator cit1=iv1.begin(); cit1!=iv1.end(); ++cit1) {
- GINAC_ASSERT(is_ex_of_type(*cit1,idx));
- if (ex_to_idx(*cit1).is_symbolic()) {
- for (exvector::const_iterator cit2=iv2.begin(); cit2!=iv2.end(); ++cit2) {
- GINAC_ASSERT(is_ex_of_type(*cit2,idx));
- if ((*cit1).is_equal(*cit2)) {
- iv_intersect.push_back(*cit1);
- break;
- }
- }
+ exvector::const_iterator cit = iv_union.begin(), citend = iv_union.end();
+ ex e;
+ if (cit != citend)
+ e = *cit++;
+ while (cit != citend) {
+ if (e.is_equal(*cit)) {
+ iv_intersect.push_back(e);
+ do {
+ cit++;
+ } while (cit != citend && e.is_equal(*cit));
+ if (cit == citend)
+ break;
}
+ e = *cit++;
}
return iv_intersect;
}
-#define TEST_PERMUTATION(A,B,C,P) \
- if ((iv3[B].is_equal(iv2[0]))&&(iv3[C].is_equal(iv2[1]))) { \
- if (antisymmetric) *sig=P; \
- return iv3[A]; \
- }
-
-ex permute_free_index_to_front(const exvector & iv3, const exvector & iv2,
- bool antisymmetric, int * sig)
+/** Given a vector iv3 of three indices and a vector iv2 of two indices
+ * where iv2 is a subset of iv3, return the (free) index that is in iv3
+ * but not in iv2 and the sign introduced by permuting that index to the
+ * front.
+ *
+ * @param iv3 Vector of 3 indices
+ * @param iv2 Vector of 2 indices, must be a subset of iv3
+ * @param sig Returns the sign introduced by permuting the free index to the
+ * front if the object carrying the indices was antisymmetric (if
+ * it's symmetric, you can just ignore the returned value).
+ * @return the free index (the one that is in iv3 but not in iv2) */
+ex permute_free_index_to_front(const exvector & iv3, const exvector & iv2, int * sig)
{
// match (return value,iv2) to iv3 by permuting indices
// iv3 is always cyclic
GINAC_ASSERT(iv2.size()==2);
*sig=1;
+
+#define TEST_PERMUTATION(A,B,C,P) \
+ if ((iv3[B].is_equal(iv2[0]))&&(iv3[C].is_equal(iv2[1]))) { \
+ *sig=P; \
+ return iv3[A]; \
+ }
TEST_PERMUTATION(0,1,2, 1);
TEST_PERMUTATION(0,2,1, -1);
throw(std::logic_error("permute_free_index_to_front(): no valid permutation found"));
}
+/** Substitute one index in a vector of expressions.
+ *
+ * @param v Vector to substitute in (will be modified)
+ * @param is Index being substituted
+ * @param ir Index to replace by
+ * @return number of performed substitutions */
unsigned subs_index_in_exvector(exvector & v, const ex & is, const ex & ir)
{
exvector::iterator it;
return replacements;
}
+/** Count number of times a given index appears in the index vector of an
+ * indexed object.
+ *
+ * @param e Indexed object
+ * @param i Index to look for
+ * @return number of times the index was found */
unsigned count_index(const ex & e, const ex & i)
{
exvector idxv=e.get_indices();
return count;
}
-ex subs_indices(const ex & e, const exvector & idxv_subs,
- const exvector & idxv_repl)
+/** Substitute multiple indices in an expression.
+ *
+ * @param e Expression to substitute in
+ * @param idxv_subs Vector of indices being substituted
+ * @param idxv_repl Vector of indices to replace by (1:1 correspondence to idxv_subs)
+ * @return expression with substituted indices */
+ex subs_indices(const ex & e, const exvector & idxv_subs, const exvector & idxv_repl)
{
GINAC_ASSERT(idxv_subs.size()==idxv_repl.size());
ex res=e;
namespace GiNaC {
#endif // ndef NO_NAMESPACE_GINAC
+
+/** This class holds one index of an indexed object. Indices can be symbolic
+ * (e.g. "mu", "i") or numeric (unsigned integer), and they can be contravariant
+ * (the default) or covariant. */
class idx : public basic
{
GINAC_DECLARE_REGISTERED_CLASS(idx, basic)
-// member functions
-
// default constructor, destructor, copy constructor assignment operator and helpers
public:
idx();
// non-virtual functions in this class
public:
- bool is_symbolic(void) const;
- unsigned get_value(void) const;
- bool is_covariant(void) const;
+ /** Check whether index is symbolic (not numeric). */
+ bool is_symbolic(void) const {return symbolic;}
+
+ /** Get numeric value of index. Undefined for symbolic indices. */
+ unsigned get_value(void) const {return value;}
+
+ /** Check whether index is covariant (not contravariant). */
+ bool is_covariant(void) const {return covariant;}
+
void setname(const std::string & n) {name=n;}
std::string getname(void) const {return name;}
// member variables
protected:
unsigned serial;
- bool symbolic;
- std::string name;
- unsigned value;
+ bool symbolic; /**< Is index symbolic? */
+ std::string name; /**< Symbolic name (if symbolic == true) */
+ unsigned value; /**< Numeric value (if symbolic == false) */
static unsigned next_serial;
- bool covariant; // x_mu, default is contravariant: x~mu
+ bool covariant; /**< x_mu, default is contravariant: x~mu */
};
// global constants
int canonicalize_indices(exvector & iv, bool antisymmetric=false);
exvector idx_intersect(const exvector & iv1, const exvector & iv2);
-ex permute_free_index_to_front(const exvector & iv3, const exvector & iv2,
- bool antisymmetric, int * sig);
+ex permute_free_index_to_front(const exvector & iv3, const exvector & iv2, int * sig);
unsigned subs_index_in_exvector(exvector & v, const ex & is, const ex & ir);
-ex subs_indices(const ex & e, const exvector & idxv_contra,
- const exvector & idxv_co);
+ex subs_indices(const ex & e, const exvector & idxv_contra, const exvector & idxv_co);
unsigned count_index(const ex & e, const ex & i);
#ifndef NO_NAMESPACE_GINAC
// public
+/** Construct symbolic Lorentz index, using an automatically generated unique name.
+ *
+ * @param cov Index is covariant (contravariant otherwise)
+ * @param oonly Index only lives in orthogonal space
+ * @param dimp Dimension of parallel space
+ * @return newly constructed index */
lorentzidx::lorentzidx(bool cov, bool oonly, unsigned dimp)
: idx(cov), orthogonal_only(oonly), dim_parallel_space(dimp)
{
tinfo_key=TINFO_lorentzidx;
}
+/** Construct symbolic Lorentz index with specified name.
+ *
+ * @param n Symbolic index name
+ * @param cov Index is covariant (contravariant otherwise)
+ * @param oonly Index only lives in orthogonal space
+ * @param dimp Dimension of parallel space
+ * @return newly constructed index */
lorentzidx::lorentzidx(const std::string & n, bool cov, bool oonly, unsigned dimp)
: idx(n,cov), orthogonal_only(oonly), dim_parallel_space(dimp)
{
tinfo_key=TINFO_lorentzidx;
}
+/** Construct symbolic Lorentz index with specified name.
+ *
+ * @param n Symbolic index name
+ * @param cov Index is covariant (contravariant otherwise)
+ * @param oonly Index only lives in orthogonal space
+ * @param dimp Dimension of parallel space
+ * @return newly constructed index */
lorentzidx::lorentzidx(const char * n, bool cov, bool oonly, unsigned dimp)
: idx(n,cov), orthogonal_only(oonly), dim_parallel_space(dimp)
{
tinfo_key=TINFO_lorentzidx;
}
+/** Construct numeric Lorentz index with specified value.
+ *
+ * @param v Numeric index value
+ * @param cov Index is covariant (contravariant otherwise)
+ * @return newly constructed index */
lorentzidx::lorentzidx(unsigned v, bool cov)
: idx(v,cov), orthogonal_only(false), dim_parallel_space(0)
{
{
debugmsg("lorentzidx constructor from archive_node", LOGLEVEL_CONSTRUCT);
n.find_bool("orthogonal_only", orthogonal_only);
- if (orthogonal_only)
- n.find_unsigned("pdim", dim_parallel_space);
+ n.find_unsigned("pdim", dim_parallel_space);
}
/** Unarchive the object. */
{
inherited::archive(n);
n.add_bool("orthogonal_only", orthogonal_only);
- if (orthogonal_only)
- n.add_unsigned("pdim", dim_parallel_space);
+ n.add_unsigned("pdim", dim_parallel_space);
}
//////////
// public
+/** Create anonymous contravariant copy of a symbolic Lorentz index. */
lorentzidx lorentzidx::create_anonymous_representative(void) const
{
GINAC_ASSERT(is_symbolic());
namespace GiNaC {
#endif // ndef NO_NAMESPACE_GINAC
+/** Class of indices for Lorentz tensors, to tell them apart from other index
+ * families like color indices. The indices of this class also support the
+ * case of P-O-decomposed D-dimensional spacetime, where the parallel space
+ * is a Minkowski-like space with integral dimension P and the orthogonal
+ * space is a Euclidean space with (possibly complex) dimension D-P. */
class lorentzidx : public idx
{
GINAC_DECLARE_REGISTERED_CLASS(lorentzidx, idx)
// non-virtual functions in this class
public:
- bool is_orthogonal_only(void) const { return orthogonal_only; }
- unsigned get_dim_parallel_space(void) const { return dim_parallel_space; }
+ /** Check whether index only lives in orthogonal space. */
+ bool is_orthogonal_only(void) const {return orthogonal_only;}
+
+ /** Return dimension of parallel space. */
+ unsigned get_dim_parallel_space(void) const {return dim_parallel_space;}
+
lorentzidx create_anonymous_representative(void) const;
// member variables
protected:
- bool orthogonal_only;
- unsigned dim_parallel_space;
+ bool orthogonal_only; /**< Symbolic index only lives in orthogonal space? */
+ unsigned dim_parallel_space; /**< Dimension of parallel space */
};
// global constants
return _ex0();
}
} else if (idx1.is_symbolic() && idx1.is_co_contra_pair(idx2)) {
- return Dim()-idx1.get_dim_parallel_space();
+ return Dim() - 2;
}
}
return this -> hold();
}
} else if (idx1.is_symbolic() &&
idx1.is_co_contra_pair(idx2)) {
- return Dim()-idx1.get_dim_parallel_space();
+ return Dim() - 2;
}
}