-
- if (flags & status_flags::evaluated) {
- GINAC_ASSERT(seq.size()>0);
- GINAC_ASSERT((seq.size()>1)||!overall_coeff.is_equal(_ex0()));
- return *this;
- }
-
- int seq_size=seq.size();
- if (seq_size==0) {
- // +(;c) -> c
- return overall_coeff;
- } else if ((seq_size==1)&&overall_coeff.is_equal(_ex0())) {
- // +(x;0) -> x
- return recombine_pair_to_ex(*(seq.begin()));
- }
- return this->hold();
-}
-
-exvector add::get_indices(void) const
-{
- // FIXME: all terms in the sum should have the same indices (compatible
- // tensors) however this is not checked, since there is no function yet
- // which compares indices (idxvector can be unsorted)
- if (seq.size()==0) {
- return exvector();
- }
- return (seq.begin())->rest.get_indices();
-}
-
-ex add::simplify_ncmul(exvector const & v) const
-{
- if (seq.size()==0) {
- return expairseq::simplify_ncmul(v);
- }
- return (*seq.begin()).rest.simplify_ncmul(v);
+
+ if (flags & status_flags::evaluated) {
+ GINAC_ASSERT(seq.size()>0);
+ GINAC_ASSERT(seq.size()>1 || !overall_coeff.is_zero());
+ return *this;
+ }
+
+ int seq_size = seq.size();
+ if (seq_size == 0) {
+ // +(;c) -> c
+ return overall_coeff;
+ } else if (seq_size == 1 && overall_coeff.is_zero()) {
+ // +(x;0) -> x
+ return recombine_pair_to_ex(*(seq.begin()));
+ } else if (!overall_coeff.is_zero() && seq[0].rest.return_type() != return_types::commutative) {
+ throw (std::logic_error("add::eval(): sum of non-commutative objects has non-zero numeric term"));
+ }
+
+ // if any terms in the sum still are purely numeric, then they are more
+ // appropriately collected into the overall coefficient
+ epvector::const_iterator last = seq.end();
+ epvector::const_iterator j = seq.begin();
+ int terms_to_collect = 0;
+ while (j != last) {
+ if (unlikely(is_a<numeric>(j->rest)))
+ ++terms_to_collect;
+ ++j;
+ }
+ if (terms_to_collect) {
+ std::auto_ptr<epvector> s(new epvector);
+ s->reserve(seq_size - terms_to_collect);
+ numeric oc = *_num1_p;
+ j = seq.begin();
+ while (j != last) {
+ if (unlikely(is_a<numeric>(j->rest)))
+ oc = oc.mul(ex_to<numeric>(j->rest)).mul(ex_to<numeric>(j->coeff));
+ else
+ s->push_back(*j);
+ ++j;
+ }
+ return (new add(s, ex_to<numeric>(overall_coeff).add_dyn(oc)))
+ ->setflag(status_flags::dynallocated);
+ }
+
+ return this->hold();
+}
+
+ex add::evalm() const
+{
+ // Evaluate children first and add up all matrices. Stop if there's one
+ // term that is not a matrix.
+ std::auto_ptr<epvector> s(new epvector);
+ s->reserve(seq.size());
+
+ bool all_matrices = true;
+ bool first_term = true;
+ matrix sum;
+
+ epvector::const_iterator it = seq.begin(), itend = seq.end();
+ while (it != itend) {
+ const ex &m = recombine_pair_to_ex(*it).evalm();
+ s->push_back(split_ex_to_pair(m));
+ if (is_a<matrix>(m)) {
+ if (first_term) {
+ sum = ex_to<matrix>(m);
+ first_term = false;
+ } else
+ sum = sum.add(ex_to<matrix>(m));
+ } else
+ all_matrices = false;
+ ++it;
+ }
+
+ if (all_matrices)
+ return sum + overall_coeff;
+ else
+ return (new add(s, overall_coeff))->setflag(status_flags::dynallocated);
+}
+
+ex add::conjugate() const
+{
+ exvector *v = 0;
+ for (size_t i=0; i<nops(); ++i) {
+ if (v) {
+ v->push_back(op(i).conjugate());
+ continue;
+ }
+ ex term = op(i);
+ ex ccterm = term.conjugate();
+ if (are_ex_trivially_equal(term, ccterm))
+ continue;
+ v = new exvector;
+ v->reserve(nops());
+ for (size_t j=0; j<i; ++j)
+ v->push_back(op(j));
+ v->push_back(ccterm);
+ }
+ if (v) {
+ ex result = add(*v);
+ delete v;
+ return result;
+ }
+ return *this;
+}
+
+ex add::real_part() const
+{
+ epvector v;
+ v.reserve(seq.size());
+ for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i)
+ if ((i->coeff).info(info_flags::real)) {
+ ex rp = (i->rest).real_part();
+ if (!rp.is_zero())
+ v.push_back(expair(rp, i->coeff));
+ } else {
+ ex rp=recombine_pair_to_ex(*i).real_part();
+ if (!rp.is_zero())
+ v.push_back(split_ex_to_pair(rp));
+ }
+ return (new add(v, overall_coeff.real_part()))
+ -> setflag(status_flags::dynallocated);
+}
+
+ex add::imag_part() const
+{
+ epvector v;
+ v.reserve(seq.size());
+ for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i)
+ if ((i->coeff).info(info_flags::real)) {
+ ex ip = (i->rest).imag_part();
+ if (!ip.is_zero())
+ v.push_back(expair(ip, i->coeff));
+ } else {
+ ex ip=recombine_pair_to_ex(*i).imag_part();
+ if (!ip.is_zero())
+ v.push_back(split_ex_to_pair(ip));
+ }
+ return (new add(v, overall_coeff.imag_part()))
+ -> setflag(status_flags::dynallocated);
+}
+
+ex add::eval_ncmul(const exvector & v) const
+{
+ if (seq.empty())
+ return inherited::eval_ncmul(v);
+ else
+ return seq.begin()->rest.eval_ncmul(v);