GiNaC  1.8.3
mul.cpp
Go to the documentation of this file.
1 
5 /*
6  * GiNaC Copyright (C) 1999-2022 Johannes Gutenberg University Mainz, Germany
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 #include "mul.h"
24 #include "add.h"
25 #include "power.h"
26 #include "operators.h"
27 #include "matrix.h"
28 #include "indexed.h"
29 #include "lst.h"
30 #include "archive.h"
31 #include "utils.h"
32 #include "symbol.h"
33 #include "compiler.h"
34 
35 #include <iostream>
36 #include <limits>
37 #include <stdexcept>
38 #include <vector>
39 
40 namespace GiNaC {
41 
44  print_func<print_latex>(&mul::do_print_latex).
45  print_func<print_csrc>(&mul::do_print_csrc).
46  print_func<print_tree>(&mul::do_print_tree).
47  print_func<print_python_repr>(&mul::do_print_python_repr))
48 
49 
50 // default constructor
53 
54 mul::mul()
55 {
56 }
57 
59 // other constructors
61 
62 // public
63 
64 mul::mul(const ex & lh, const ex & rh)
65 {
67  construct_from_2_ex(lh,rh);
69 }
70 
71 mul::mul(const exvector & v)
72 {
76 }
77 
78 mul::mul(const epvector & v)
79 {
83 }
84 
85 mul::mul(const epvector & v, const ex & oc, bool do_index_renaming)
86 {
87  overall_coeff = oc;
88  construct_from_epvector(v, do_index_renaming);
90 }
91 
93 {
95  construct_from_epvector(std::move(vp));
97 }
98 
99 mul::mul(epvector && vp, const ex & oc, bool do_index_renaming)
100 {
101  overall_coeff = oc;
102  construct_from_epvector(std::move(vp), do_index_renaming);
104 }
105 
106 mul::mul(const ex & lh, const ex & mh, const ex & rh)
107 {
109  factors.reserve(3);
110  factors.push_back(lh);
111  factors.push_back(mh);
112  factors.push_back(rh);
116 }
117 
119 // archiving
121 
123 // functions overriding virtual functions from base classes
125 
126 void mul::print_overall_coeff(const print_context & c, const char *mul_sym) const
127 {
128  const numeric &coeff = ex_to<numeric>(overall_coeff);
129  if (coeff.csgn() == -1)
130  c.s << '-';
131  if (!coeff.is_equal(*_num1_p) &&
132  !coeff.is_equal(*_num_1_p)) {
133  if (coeff.is_rational()) {
134  if (coeff.is_negative())
135  (-coeff).print(c);
136  else
137  coeff.print(c);
138  } else {
139  if (coeff.csgn() == -1)
140  (-coeff).print(c, precedence());
141  else
142  coeff.print(c, precedence());
143  }
144  c.s << mul_sym;
145  }
146 }
147 
148 void mul::do_print(const print_context & c, unsigned level) const
149 {
150  if (precedence() <= level)
151  c.s << '(';
152 
153  print_overall_coeff(c, "*");
154 
155  bool first = true;
156  for (auto & it : seq) {
157  if (!first)
158  c.s << '*';
159  else
160  first = false;
162  }
163 
164  if (precedence() <= level)
165  c.s << ')';
166 }
167 
168 void mul::do_print_latex(const print_latex & c, unsigned level) const
169 {
170  if (precedence() <= level)
171  c.s << "{(";
172 
173  print_overall_coeff(c, " ");
174 
175  // Separate factors into those with negative numeric exponent
176  // and all others
177  exvector neg_powers, others;
178  for (auto & it : seq) {
179  GINAC_ASSERT(is_exactly_a<numeric>(it.coeff));
180  if (ex_to<numeric>(it.coeff).is_negative())
181  neg_powers.push_back(recombine_pair_to_ex(expair(it.rest, -it.coeff)));
182  else
183  others.push_back(recombine_pair_to_ex(it));
184  }
185 
186  if (!neg_powers.empty()) {
187 
188  // Factors with negative exponent are printed as a fraction
189  c.s << "\\frac{";
190  mul(others).eval().print(c);
191  c.s << "}{";
192  mul(neg_powers).eval().print(c);
193  c.s << "}";
194 
195  } else {
196 
197  // All other factors are printed in the ordinary way
198  for (auto & vit : others) {
199  c.s << ' ';
200  vit.print(c, precedence());
201  }
202  }
203 
204  if (precedence() <= level)
205  c.s << ")}";
206 }
207 
208 void mul::do_print_csrc(const print_csrc & c, unsigned level) const
209 {
210  if (precedence() <= level)
211  c.s << "(";
212 
213  if (!overall_coeff.is_equal(_ex1)) {
215  c.s << "-";
216  else {
218  c.s << "*";
219  }
220  }
221 
222  // Print arguments, separated by "*" or "/"
223  auto it = seq.begin(), itend = seq.end();
224  while (it != itend) {
225 
226  // If the first argument is a negative integer power, it gets printed as "1.0/<expr>"
227  bool needclosingparenthesis = false;
228  if (it == seq.begin() && it->coeff.info(info_flags::negint)) {
229  if (is_a<print_csrc_cl_N>(c)) {
230  c.s << "recip(";
231  needclosingparenthesis = true;
232  } else
233  c.s << "1.0/";
234  }
235 
236  // If the exponent is 1 or -1, it is left out
237  if (it->coeff.is_equal(_ex1) || it->coeff.is_equal(_ex_1))
238  it->rest.print(c, precedence());
239  else if (it->coeff.info(info_flags::negint))
240  ex(power(it->rest, -ex_to<numeric>(it->coeff))).print(c, level);
241  else
242  ex(power(it->rest, ex_to<numeric>(it->coeff))).print(c, level);
243 
244  if (needclosingparenthesis)
245  c.s << ")";
246 
247  // Separator is "/" for negative integer powers, "*" otherwise
248  ++it;
249  if (it != itend) {
250  if (it->coeff.info(info_flags::negint))
251  c.s << "/";
252  else
253  c.s << "*";
254  }
255  }
256 
257  if (precedence() <= level)
258  c.s << ")";
259 }
260 
261 void mul::do_print_python_repr(const print_python_repr & c, unsigned level) const
262 {
263  c.s << class_name() << '(';
264  op(0).print(c);
265  for (size_t i=1; i<nops(); ++i) {
266  c.s << ',';
267  op(i).print(c);
268  }
269  c.s << ')';
270 }
271 
272 bool mul::info(unsigned inf) const
273 {
274  switch (inf) {
279  case info_flags::real:
281  case info_flags::integer:
284  case info_flags::even:
287  for (auto & it : seq) {
288  if (!recombine_pair_to_ex(it).info(inf))
289  return false;
290  }
292  return true;
293  return overall_coeff.info(inf);
294  }
296  case info_flags::negative: {
298  return true;
300  return true;
302  return false;
303 
304  bool pos = true;
305  for (auto & it : seq) {
306  const ex& factor = recombine_pair_to_ex(it);
308  continue;
309  else if (factor.info(info_flags::negative))
310  pos = !pos;
311  else
312  return false;
313  }
315  pos = !pos;
317  return (inf == info_flags::positive? pos : !pos);
318  }
321  return true;
322  bool pos = true;
323  for (auto & it : seq) {
324  const ex& factor = recombine_pair_to_ex(it);
326  continue;
327  else if (factor.info(info_flags::negative))
328  pos = !pos;
329  else
330  return false;
331  }
332  return (overall_coeff.info(info_flags::negative)? !pos : pos);
333  }
334  case info_flags::posint:
335  case info_flags::negint: {
336  bool pos = true;
337  for (auto & it : seq) {
338  const ex& factor = recombine_pair_to_ex(it);
340  continue;
341  else if (factor.info(info_flags::negint))
342  pos = !pos;
343  else
344  return false;
345  }
347  pos = !pos;
349  return false;
350  return (inf ==info_flags::posint? pos : !pos);
351  }
352  case info_flags::nonnegint: {
353  bool pos = true;
354  for (auto & it : seq) {
355  const ex& factor = recombine_pair_to_ex(it);
357  continue;
358  else if (factor.info(info_flags::negint))
359  pos = !pos;
360  else
361  return false;
362  }
364  pos = !pos;
366  return false;
367  return pos;
368  }
369  case info_flags::indefinite: {
371  return true;
373  return false;
374  for (auto & it : seq) {
375  const ex& term = recombine_pair_to_ex(it);
377  return false;
378  }
380  return true;
381  }
382  }
383  return inherited::info(inf);
384 }
385 
386 bool mul::is_polynomial(const ex & var) const
387 {
388  for (auto & it : seq) {
389  if (!it.rest.is_polynomial(var) ||
390  (it.rest.has(var) && !it.coeff.info(info_flags::nonnegint))) {
391  return false;
392  }
393  }
394  return true;
395 }
396 
397 int mul::degree(const ex & s) const
398 {
399  // Sum up degrees of factors
400  int deg_sum = 0;
401  for (auto & it : seq) {
402  if (ex_to<numeric>(it.coeff).is_integer())
403  deg_sum += recombine_pair_to_ex(it).degree(s);
404  else {
405  if (it.rest.has(s))
406  throw std::runtime_error("mul::degree() undefined degree because of non-integer exponent");
407  }
408  }
409  return deg_sum;
410 }
411 
412 int mul::ldegree(const ex & s) const
413 {
414  // Sum up degrees of factors
415  int deg_sum = 0;
416  for (auto & it : seq) {
417  if (ex_to<numeric>(it.coeff).is_integer())
418  deg_sum += recombine_pair_to_ex(it).ldegree(s);
419  else {
420  if (it.rest.has(s))
421  throw std::runtime_error("mul::ldegree() undefined degree because of non-integer exponent");
422  }
423  }
424  return deg_sum;
425 }
426 
427 ex mul::coeff(const ex & s, int n) const
428 {
429  exvector coeffseq;
430  coeffseq.reserve(seq.size()+1);
431 
432  if (n==0) {
433  // product of individual coeffs
434  // if a non-zero power of s is found, the resulting product will be 0
435  for (auto & it : seq)
436  coeffseq.push_back(recombine_pair_to_ex(it).coeff(s,n));
437  coeffseq.push_back(overall_coeff);
438  return dynallocate<mul>(coeffseq);
439  }
440 
441  bool coeff_found = false;
442  for (auto & it : seq) {
443  ex t = recombine_pair_to_ex(it);
444  ex c = t.coeff(s, n);
445  if (!c.is_zero()) {
446  coeffseq.push_back(c);
447  coeff_found = 1;
448  } else {
449  coeffseq.push_back(t);
450  }
451  }
452  if (coeff_found) {
453  coeffseq.push_back(overall_coeff);
454  return dynallocate<mul>(coeffseq);
455  }
456 
457  return _ex0;
458 }
459 
468 ex mul::eval() const
469 {
471  GINAC_ASSERT(seq.size()>0);
472  GINAC_ASSERT(seq.size()>1 || !overall_coeff.is_equal(_ex1));
473  return *this;
474  }
475 
476  const epvector evaled = evalchildren();
477  if (unlikely(!evaled.empty())) {
478  // start over evaluating a new object
479  return dynallocate<mul>(std::move(evaled), overall_coeff);
480  }
481 
482  size_t seq_size = seq.size();
483  if (overall_coeff.is_zero()) {
484  // *(...,x;0) -> 0
485  return _ex0;
486  } else if (seq_size==0) {
487  // *(;c) -> c
488  return overall_coeff;
489  } else if (seq_size==1 && overall_coeff.is_equal(_ex1)) {
490  // *(x;1) -> x
491  return recombine_pair_to_ex(*(seq.begin()));
492  } else if ((seq_size==1) &&
493  is_exactly_a<add>((*seq.begin()).rest) &&
494  ex_to<numeric>((*seq.begin()).coeff).is_equal(*_num1_p)) {
495  // *(+(x,y,...);c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
496  const add & addref = ex_to<add>((*seq.begin()).rest);
497  epvector distrseq;
498  distrseq.reserve(addref.seq.size());
499  for (auto & it : addref.seq) {
500  distrseq.push_back(addref.combine_pair_with_coeff_to_pair(it, overall_coeff));
501  }
502  return dynallocate<add>(std::move(distrseq),
503  ex_to<numeric>(addref.overall_coeff).mul_dyn(ex_to<numeric>(overall_coeff)))
504  .setflag(status_flags::evaluated);
505  } else if ((seq_size >= 2) && (! (flags & status_flags::expanded))) {
506  // Strip the content and the unit part from each term. Thus
507  // things like (-x+a)*(3*x-3*a) automagically turn into - 3*(x-a)^2
508 
509  auto i = seq.begin(), last = seq.end();
510  auto j = seq.begin();
511  epvector s;
512  numeric oc = *_num1_p;
513  bool something_changed = false;
514  while (i!=last) {
515  if (likely(! (is_a<add>(i->rest) && i->coeff.is_equal(_ex1)))) {
516  // power::eval has such a rule, no need to handle powers here
517  ++i;
518  continue;
519  }
520 
521  // XXX: What is the best way to check if the polynomial is a primitive?
522  numeric c = i->rest.integer_content();
523  const numeric lead_coeff =
524  ex_to<numeric>(ex_to<add>(i->rest).seq.begin()->coeff).div(c);
525  const bool canonicalizable = lead_coeff.is_integer();
526 
527  // XXX: The main variable is chosen in a random way, so this code
528  // does NOT transform the term into the canonical form (thus, in some
529  // very unlucky event it can even loop forever). Hopefully the main
530  // variable will be the same for all terms in *this
531  const bool unit_normal = lead_coeff.is_pos_integer();
532  if (likely((c == *_num1_p) && ((! canonicalizable) || unit_normal))) {
533  ++i;
534  continue;
535  }
536 
537  if (! something_changed) {
538  s.reserve(seq_size);
539  something_changed = true;
540  }
541 
542  while ((j!=i) && (j!=last)) {
543  s.push_back(*j);
544  ++j;
545  }
546 
547  if (! unit_normal)
548  c = c.mul(*_num_1_p);
549 
550  oc = oc.mul(c);
551 
552  // divide add by the number in place to save at least 2 .eval() calls
553  const add& addref = ex_to<add>(i->rest);
554  add & primitive = dynallocate<add>(addref);
556  primitive.overall_coeff = ex_to<numeric>(primitive.overall_coeff).div_dyn(c);
557  for (auto & ai : primitive.seq)
558  ai.coeff = ex_to<numeric>(ai.coeff).div_dyn(c);
559 
560  s.push_back(expair(primitive, _ex1));
561 
562  ++i;
563  ++j;
564  }
565  if (something_changed) {
566  while (j!=last) {
567  s.push_back(*j);
568  ++j;
569  }
570  return dynallocate<mul>(std::move(s), ex_to<numeric>(overall_coeff).mul_dyn(oc));
571  }
572  }
573 
574  return this->hold();
575 }
576 
577 ex mul::evalf() const
578 {
579  epvector s;
580  s.reserve(seq.size());
581 
582  for (auto & it : seq)
583  s.push_back(expair(it.rest.evalf(), it.coeff));
584  return dynallocate<mul>(std::move(s), overall_coeff.evalf());
585 }
586 
587 void mul::find_real_imag(ex & rp, ex & ip) const
588 {
589  rp = overall_coeff.real_part();
590  ip = overall_coeff.imag_part();
591  for (auto & it : seq) {
593  ex new_rp = factor.real_part();
594  ex new_ip = factor.imag_part();
595  if (new_ip.is_zero()) {
596  rp *= new_rp;
597  ip *= new_rp;
598  } else {
599  ex temp = rp*new_rp - ip*new_ip;
600  ip = ip*new_rp + rp*new_ip;
601  rp = temp;
602  }
603  }
604  rp = rp.expand();
605  ip = ip.expand();
606 }
607 
609 {
610  ex rp, ip;
611  find_real_imag(rp, ip);
612  return rp;
613 }
614 
616 {
617  ex rp, ip;
618  find_real_imag(rp, ip);
619  return ip;
620 }
621 
622 ex mul::evalm() const
623 {
624  // numeric*matrix
625  if (seq.size() == 1 && seq[0].coeff.is_equal(_ex1)
626  && is_a<matrix>(seq[0].rest))
627  return ex_to<matrix>(seq[0].rest).mul(ex_to<numeric>(overall_coeff));
628 
629  // Evaluate children first, look whether there are any matrices at all
630  // (there can be either no matrices or one matrix; if there were more
631  // than one matrix, it would be a non-commutative product)
632  epvector s;
633  s.reserve(seq.size());
634 
635  bool have_matrix = false;
636  epvector::iterator the_matrix;
637 
638  for (auto & it : seq) {
639  const ex &m = recombine_pair_to_ex(it).evalm();
640  s.push_back(split_ex_to_pair(m));
641  if (is_a<matrix>(m)) {
642  have_matrix = true;
643  the_matrix = s.end() - 1;
644  }
645  }
646 
647  if (have_matrix) {
648 
649  // The product contained a matrix. We will multiply all other factors
650  // into that matrix.
651  matrix m = ex_to<matrix>(the_matrix->rest);
652  s.erase(the_matrix);
653  ex scalar = dynallocate<mul>(std::move(s), overall_coeff);
654  return m.mul_scalar(scalar);
655 
656  } else
657  return dynallocate<mul>(std::move(s), overall_coeff);
658 }
659 
660 ex mul::eval_ncmul(const exvector & v) const
661 {
662  if (seq.empty())
663  return inherited::eval_ncmul(v);
664 
665  // Find first noncommutative element and call its eval_ncmul()
666  for (auto & it : seq)
667  if (it.rest.return_type() == return_types::noncommutative)
668  return it.rest.eval_ncmul(v);
669  return inherited::eval_ncmul(v);
670 }
671 
672 bool tryfactsubs(const ex & origfactor, const ex & patternfactor, int & nummatches, exmap& repls)
673 {
674  ex origbase;
675  int origexponent;
676  int origexpsign;
677 
678  if (is_exactly_a<power>(origfactor) && origfactor.op(1).info(info_flags::integer)) {
679  origbase = origfactor.op(0);
680  int expon = ex_to<numeric>(origfactor.op(1)).to_int();
681  origexponent = expon > 0 ? expon : -expon;
682  origexpsign = expon > 0 ? 1 : -1;
683  } else {
684  origbase = origfactor;
685  origexponent = 1;
686  origexpsign = 1;
687  }
688 
689  ex patternbase;
690  int patternexponent;
691  int patternexpsign;
692 
693  if (is_exactly_a<power>(patternfactor) && patternfactor.op(1).info(info_flags::integer)) {
694  patternbase = patternfactor.op(0);
695  int expon = ex_to<numeric>(patternfactor.op(1)).to_int();
696  patternexponent = expon > 0 ? expon : -expon;
697  patternexpsign = expon > 0 ? 1 : -1;
698  } else {
699  patternbase = patternfactor;
700  patternexponent = 1;
701  patternexpsign = 1;
702  }
703 
704  exmap saverepls = repls;
705  if (origexponent < patternexponent || origexpsign != patternexpsign || !origbase.match(patternbase,saverepls))
706  return false;
707  repls = saverepls;
708 
709  int newnummatches = origexponent / patternexponent;
710  if (newnummatches < nummatches)
711  nummatches = newnummatches;
712  return true;
713 }
714 
723 bool algebraic_match_mul_with_mul(const mul &e, const ex &pat, exmap& repls,
724  int factor, int &nummatches, const std::vector<bool> &subsed,
725  std::vector<bool> &matched)
726 {
727  GINAC_ASSERT(subsed.size() == e.nops());
728  GINAC_ASSERT(matched.size() == e.nops());
729 
730  if (factor == (int)pat.nops())
731  return true;
732 
733  for (size_t i=0; i<e.nops(); ++i) {
734  if(subsed[i] || matched[i])
735  continue;
736  exmap newrepls = repls;
737  int newnummatches = nummatches;
738  if (tryfactsubs(e.op(i), pat.op(factor), newnummatches, newrepls)) {
739  matched[i] = true;
740  if (algebraic_match_mul_with_mul(e, pat, newrepls, factor+1,
741  newnummatches, subsed, matched)) {
742  repls = newrepls;
743  nummatches = newnummatches;
744  return true;
745  }
746  else
747  matched[i] = false;
748  }
749  }
750 
751  return false;
752 }
753 
754 bool mul::has(const ex & pattern, unsigned options) const
755 {
757  return basic::has(pattern,options);
758  if(is_a<mul>(pattern)) {
759  exmap repls;
760  int nummatches = std::numeric_limits<int>::max();
761  std::vector<bool> subsed(nops(), false);
762  std::vector<bool> matched(nops(), false);
763  if(algebraic_match_mul_with_mul(*this, pattern, repls, 0, nummatches,
764  subsed, matched))
765  return true;
766  }
767  return basic::has(pattern, options);
768 }
769 
770 ex mul::algebraic_subs_mul(const exmap & m, unsigned options) const
771 {
772  std::vector<bool> subsed(nops(), false);
773  ex divide_by = 1;
774  ex multiply_by = 1;
775 
776  for (auto & it : m) {
777 
778  if (is_exactly_a<mul>(it.first)) {
779 retry1:
780  int nummatches = std::numeric_limits<int>::max();
781  std::vector<bool> currsubsed(nops(), false);
782  exmap repls;
783 
784  if (!algebraic_match_mul_with_mul(*this, it.first, repls, 0, nummatches, subsed, currsubsed))
785  continue;
786 
787  for (size_t j=0; j<subsed.size(); j++)
788  if (currsubsed[j])
789  subsed[j] = true;
790  ex subsed_pattern
791  = it.first.subs(repls, subs_options::no_pattern);
792  divide_by *= pow(subsed_pattern, nummatches);
793  ex subsed_result
794  = it.second.subs(repls, subs_options::no_pattern);
795  multiply_by *= pow(subsed_result, nummatches);
796  goto retry1;
797 
798  } else {
799 
800  for (size_t j=0; j<this->nops(); j++) {
801  int nummatches = std::numeric_limits<int>::max();
802  exmap repls;
803  if (!subsed[j] && tryfactsubs(op(j), it.first, nummatches, repls)){
804  subsed[j] = true;
805  ex subsed_pattern
806  = it.first.subs(repls, subs_options::no_pattern);
807  divide_by *= pow(subsed_pattern, nummatches);
808  ex subsed_result
809  = it.second.subs(repls, subs_options::no_pattern);
810  multiply_by *= pow(subsed_result, nummatches);
811  }
812  }
813  }
814  }
815 
816  bool subsfound = false;
817  for (size_t i=0; i<subsed.size(); i++) {
818  if (subsed[i]) {
819  subsfound = true;
820  break;
821  }
822  }
823  if (!subsfound)
825 
826  return ((*this)/divide_by)*multiply_by;
827 }
828 
830 {
831  // The base class' method is wrong here because we have to be careful at
832  // branch cuts. power::conjugate takes care of that already, so use it.
833  std::unique_ptr<epvector> newepv(nullptr);
834  for (auto i=seq.begin(); i!=seq.end(); ++i) {
835  if (newepv) {
836  newepv->push_back(split_ex_to_pair(recombine_pair_to_ex(*i).conjugate()));
837  continue;
838  }
839  ex x = recombine_pair_to_ex(*i);
840  ex c = x.conjugate();
841  if (c.is_equal(x)) {
842  continue;
843  }
844  newepv.reset(new epvector);
845  newepv->reserve(seq.size());
846  for (auto j=seq.begin(); j!=i; ++j) {
847  newepv->push_back(*j);
848  }
849  newepv->push_back(split_ex_to_pair(c));
850  }
852  if (!newepv && are_ex_trivially_equal(x, overall_coeff)) {
853  return *this;
854  }
855  return thisexpairseq(newepv ? std::move(*newepv) : seq, x);
856 }
857 
858 
859 // protected
860 
863 ex mul::derivative(const symbol & s) const
864 {
865  size_t num = seq.size();
866  exvector addseq;
867  addseq.reserve(num);
868 
869  // D(a*b*c) = D(a)*b*c + a*D(b)*c + a*b*D(c)
870  epvector mulseq = seq;
871  auto i = seq.begin(), end = seq.end();
872  auto i2 = mulseq.begin();
873  while (i != end) {
874  expair ep = split_ex_to_pair(pow(i->rest, i->coeff - _ex1) *
875  i->rest.diff(s));
876  ep.swap(*i2);
877  addseq.push_back(dynallocate<mul>(mulseq, overall_coeff * i->coeff));
878  ep.swap(*i2);
879  ++i; ++i2;
880  }
881  return dynallocate<add>(addseq);
882 }
883 
884 int mul::compare_same_type(const basic & other) const
885 {
886  return inherited::compare_same_type(other);
887 }
888 
889 unsigned mul::return_type() const
890 {
891  if (seq.empty()) {
892  // mul without factors: should not happen, but commutates
894  }
895 
896  bool all_commutative = true;
897  epvector::const_iterator noncommutative_element; // point to first found nc element
898 
899  epvector::const_iterator i = seq.begin(), end = seq.end();
900  while (i != end) {
901  unsigned rt = i->rest.return_type();
903  return rt; // one ncc -> mul also ncc
904  if ((rt == return_types::noncommutative) && (all_commutative)) {
905  // first nc element found, remember position
906  noncommutative_element = i;
907  all_commutative = false;
908  }
909  if ((rt == return_types::noncommutative) && (!all_commutative)) {
910  // another nc element found, compare type_infos
911  if (noncommutative_element->rest.return_type_tinfo() != i->rest.return_type_tinfo()) {
912  // different types -> mul is ncc
914  }
915  }
916  ++i;
917  }
918  // all factors checked
919  return all_commutative ? return_types::commutative : return_types::noncommutative;
920 }
921 
923 {
924  if (seq.empty())
925  return make_return_type_t<mul>(); // mul without factors: should not happen
926 
927  // return type_info of first noncommutative element
928  for (auto & it : seq)
929  if (it.rest.return_type() == return_types::noncommutative)
930  return it.rest.return_type_tinfo();
931 
932  // no noncommutative element found, should not happen
933  return make_return_type_t<mul>();
934 }
935 
936 ex mul::thisexpairseq(const epvector & v, const ex & oc, bool do_index_renaming) const
937 {
938  return dynallocate<mul>(v, oc, do_index_renaming);
939 }
940 
941 ex mul::thisexpairseq(epvector && vp, const ex & oc, bool do_index_renaming) const
942 {
943  return dynallocate<mul>(std::move(vp), oc, do_index_renaming);
944 }
945 
947 {
948  if (is_exactly_a<power>(e)) {
949  const power & powerref = ex_to<power>(e);
950  if (is_exactly_a<numeric>(powerref.exponent))
951  return expair(powerref.basis,powerref.exponent);
952  }
953  return expair(e,_ex1);
954 }
955 
957  const ex & c) const
958 {
959  GINAC_ASSERT(is_exactly_a<numeric>(c));
960 
961  // First, try a common shortcut:
962  if (is_exactly_a<symbol>(e))
963  return expair(e, c);
964 
965  // trivial case: exponent 1
966  if (c.is_equal(_ex1))
967  return split_ex_to_pair(e);
968 
969  // to avoid duplication of power simplification rules,
970  // we create a temporary power object
971  // otherwise it would be hard to correctly evaluate
972  // expression like (4^(1/3))^(3/2)
973  return split_ex_to_pair(pow(e,c));
974 }
975 
977  const ex & c) const
978 {
979  GINAC_ASSERT(is_exactly_a<numeric>(p.coeff));
980  GINAC_ASSERT(is_exactly_a<numeric>(c));
981 
982  // First, try a common shortcut:
983  if (is_exactly_a<symbol>(p.rest))
984  return expair(p.rest, p.coeff * c);
985 
986  // trivial case: exponent 1
987  if (c.is_equal(_ex1))
988  return p;
989  if (p.coeff.is_equal(_ex1))
990  return expair(p.rest, c);
991 
992  // to avoid duplication of power simplification rules,
993  // we create a temporary power object
994  // otherwise it would be hard to correctly evaluate
995  // expression like (4^(1/3))^(3/2)
997 }
998 
1000 {
1001  if (p.coeff.is_equal(_ex1))
1002  return p.rest;
1003  else
1004  return dynallocate<power>(p.rest, p.coeff);
1005 }
1006 
1008 {
1009  if (is_exactly_a<mul>(it->rest) &&
1010  ex_to<numeric>(it->coeff).is_integer()) {
1011  // combined pair is product with integer power -> expand it
1013  return true;
1014  }
1015  if (is_exactly_a<numeric>(it->rest)) {
1016  if (it->coeff.is_equal(_ex1)) {
1017  // pair has coeff 1 and must be moved to the end
1018  return true;
1019  }
1021  if (!ep.is_equal(*it)) {
1022  // combined pair is a numeric power which can be simplified
1023  *it = ep;
1024  return true;
1025  }
1026  }
1027  return false;
1028 }
1029 
1031 {
1032  return _ex1;
1033 }
1034 
1036 {
1037  GINAC_ASSERT(is_exactly_a<numeric>(overall_coeff));
1038  GINAC_ASSERT(is_exactly_a<numeric>(c));
1039  overall_coeff = ex_to<numeric>(overall_coeff).mul_dyn(ex_to<numeric>(c));
1040 }
1041 
1042 void mul::combine_overall_coeff(const ex & c1, const ex & c2)
1043 {
1044  GINAC_ASSERT(is_exactly_a<numeric>(overall_coeff));
1045  GINAC_ASSERT(is_exactly_a<numeric>(c1));
1046  GINAC_ASSERT(is_exactly_a<numeric>(c2));
1047  overall_coeff = ex_to<numeric>(overall_coeff).mul_dyn(ex_to<numeric>(c1).power(ex_to<numeric>(c2)));
1048 }
1049 
1050 bool mul::can_make_flat(const expair & p) const
1051 {
1052  GINAC_ASSERT(is_exactly_a<numeric>(p.coeff));
1053 
1054  // (x*y)^c == x^c*y^c if c ∈ ℤ
1055  return p.coeff.info(info_flags::integer);
1056 }
1057 
1059 {
1060  if (is_exactly_a<mul>(e)) {
1061  for (auto & it : ex_to<mul>(e).seq) {
1062  if (is_exactly_a<add>(it.rest) && it.coeff.info(info_flags::posint))
1063  return true;
1064  }
1065  } else if (is_exactly_a<power>(e)) {
1066  if (is_exactly_a<add>(e.op(0)) && e.op(1).info(info_flags::posint))
1067  return true;
1068  }
1069  return false;
1070 }
1071 
1072 ex mul::expand(unsigned options) const
1073 {
1074  // Check for trivial case: expanding the monomial (~ 30% of all calls)
1075  bool monomial_case = true;
1076  for (const auto & i : seq) {
1077  if (!is_a<symbol>(i.rest) || !i.coeff.info(info_flags::integer)) {
1078  monomial_case = false;
1079  break;
1080  }
1081  }
1082  if (monomial_case) {
1084  return *this;
1085  }
1086 
1087  // do not rename indices if the object has no indices at all
1091 
1092  const bool skip_idx_rename = !(options & expand_options::expand_rename_idx);
1093 
1094  // First, expand the children
1095  epvector expanded = expandchildren(options);
1096  const epvector & expanded_seq = (expanded.empty() ? seq : expanded);
1097 
1098  // Now, look for all the factors that are sums and multiply each one out
1099  // with the next one that is found while collecting the factors which are
1100  // not sums
1101  ex last_expanded = _ex1;
1102 
1103  epvector non_adds;
1104  non_adds.reserve(expanded_seq.size());
1105 
1106  for (const auto & cit : expanded_seq) {
1107  if (is_exactly_a<add>(cit.rest) &&
1108  (cit.coeff.is_equal(_ex1))) {
1109  if (is_exactly_a<add>(last_expanded)) {
1110 
1111  // Expand a product of two sums, aggressive version.
1112  // Caring for the overall coefficients in separate loops can
1113  // sometimes give a performance gain of up to 15%!
1114 
1115  const int sizedifference = ex_to<add>(last_expanded).seq.size()-ex_to<add>(cit.rest).seq.size();
1116  // add2 is for the inner loop and should be the bigger of the two sums
1117  // in the presence of asymptotically good sorting:
1118  const add& add1 = (sizedifference<0 ? ex_to<add>(last_expanded) : ex_to<add>(cit.rest));
1119  const add& add2 = (sizedifference<0 ? ex_to<add>(cit.rest) : ex_to<add>(last_expanded));
1120  epvector distrseq;
1121  distrseq.reserve(add1.seq.size()+add2.seq.size());
1122 
1123  // Multiply add2 with the overall coefficient of add1 and append it to distrseq:
1124  if (!add1.overall_coeff.is_zero()) {
1125  if (add1.overall_coeff.is_equal(_ex1))
1126  distrseq.insert(distrseq.end(), add2.seq.begin(), add2.seq.end());
1127  else
1128  for (const auto & i : add2.seq)
1129  distrseq.push_back(expair(i.rest, ex_to<numeric>(i.coeff).mul_dyn(ex_to<numeric>(add1.overall_coeff))));
1130  }
1131 
1132  // Multiply add1 with the overall coefficient of add2 and append it to distrseq:
1133  if (!add2.overall_coeff.is_zero()) {
1134  if (add2.overall_coeff.is_equal(_ex1))
1135  distrseq.insert(distrseq.end(), add1.seq.begin(), add1.seq.end());
1136  else
1137  for (const auto & i : add1.seq)
1138  distrseq.push_back(expair(i.rest, ex_to<numeric>(i.coeff).mul_dyn(ex_to<numeric>(add2.overall_coeff))));
1139  }
1140 
1141  // Compute the new overall coefficient and put it together:
1142  ex tmp_accu = dynallocate<add>(distrseq, add1.overall_coeff*add2.overall_coeff);
1143 
1144  exvector add1_dummy_indices, add2_dummy_indices, add_indices;
1145  lst dummy_subs;
1146 
1147  if (!skip_idx_rename) {
1148  for (const auto & i : add1.seq) {
1149  add_indices = get_all_dummy_indices_safely(i.rest);
1150  add1_dummy_indices.insert(add1_dummy_indices.end(), add_indices.begin(), add_indices.end());
1151  }
1152  for (const auto & i : add2.seq) {
1153  add_indices = get_all_dummy_indices_safely(i.rest);
1154  add2_dummy_indices.insert(add2_dummy_indices.end(), add_indices.begin(), add_indices.end());
1155  }
1156 
1157  sort(add1_dummy_indices.begin(), add1_dummy_indices.end(), ex_is_less());
1158  sort(add2_dummy_indices.begin(), add2_dummy_indices.end(), ex_is_less());
1159  dummy_subs = rename_dummy_indices_uniquely(add1_dummy_indices, add2_dummy_indices);
1160  }
1161 
1162  // Multiply explicitly all non-numeric terms of add1 and add2:
1163  for (const auto & i2 : add2.seq) {
1164  // We really have to combine terms here in order to compactify
1165  // the result. Otherwise it would become waayy tooo bigg.
1166  numeric oc(*_num0_p);
1167  epvector distrseq2;
1168  distrseq2.reserve(add1.seq.size());
1169  const ex i2_new = (skip_idx_rename || (dummy_subs.op(0).nops() == 0) ?
1170  i2.rest :
1171  i2.rest.subs(ex_to<lst>(dummy_subs.op(0)),
1172  ex_to<lst>(dummy_subs.op(1)), subs_options::no_pattern));
1173  for (const auto & i1 : add1.seq) {
1174  // Don't push_back expairs which might have a rest that evaluates to a numeric,
1175  // since that would violate an invariant of expairseq:
1176  const ex rest = dynallocate<mul>(i1.rest, i2_new);
1177  if (is_exactly_a<numeric>(rest)) {
1178  oc += ex_to<numeric>(rest).mul(ex_to<numeric>(i1.coeff).mul(ex_to<numeric>(i2.coeff)));
1179  } else {
1180  distrseq2.push_back(expair(rest, ex_to<numeric>(i1.coeff).mul_dyn(ex_to<numeric>(i2.coeff))));
1181  }
1182  }
1183  tmp_accu += dynallocate<add>(std::move(distrseq2), oc);
1184  }
1185  last_expanded = tmp_accu;
1186  } else {
1187  if (!last_expanded.is_equal(_ex1))
1188  non_adds.push_back(split_ex_to_pair(last_expanded));
1189  last_expanded = cit.rest;
1190  }
1191 
1192  } else {
1193  non_adds.push_back(cit);
1194  }
1195  }
1196 
1197  // Now the only remaining thing to do is to multiply the factors which
1198  // were not sums into the "last_expanded" sum
1199  if (is_exactly_a<add>(last_expanded)) {
1200  size_t n = last_expanded.nops();
1201  exvector distrseq;
1202  distrseq.reserve(n);
1203  exvector va;
1204  if (! skip_idx_rename) {
1205  va = get_all_dummy_indices_safely(mul(non_adds));
1206  sort(va.begin(), va.end(), ex_is_less());
1207  }
1208 
1209  for (size_t i=0; i<n; ++i) {
1210  epvector factors = non_adds;
1211  if (skip_idx_rename)
1212  factors.push_back(split_ex_to_pair(last_expanded.op(i)));
1213  else
1214  factors.push_back(split_ex_to_pair(rename_dummy_indices_uniquely(va, last_expanded.op(i))));
1215  ex term = dynallocate<mul>(factors, overall_coeff);
1216  if (can_be_further_expanded(term)) {
1217  distrseq.push_back(term.expand());
1218  } else {
1219  if (options == 0)
1220  ex_to<basic>(term).setflag(status_flags::expanded);
1221  distrseq.push_back(term);
1222  }
1223  }
1224 
1225  return dynallocate<add>(distrseq).setflag(options == 0 ? status_flags::expanded : 0);
1226  }
1227 
1228  non_adds.push_back(split_ex_to_pair(last_expanded));
1229  ex result = dynallocate<mul>(non_adds, overall_coeff);
1230  if (can_be_further_expanded(result)) {
1231  return result.expand();
1232  } else {
1233  if (options == 0)
1234  ex_to<basic>(result).setflag(status_flags::expanded);
1235  return result;
1236  }
1237 }
1238 
1239 
1241 // new virtual functions which can be overridden by derived classes
1243 
1244 // none
1245 
1247 // non-virtual functions in this class
1249 
1250 
1259 {
1260  auto cit = seq.begin(), last = seq.end();
1261  while (cit!=last) {
1262  const ex & factor = recombine_pair_to_ex(*cit);
1263  const ex & expanded_factor = factor.expand(options);
1264  if (!are_ex_trivially_equal(factor,expanded_factor)) {
1265 
1266  // something changed, copy seq, eval and return it
1267  epvector s;
1268  s.reserve(seq.size());
1269 
1270  // copy parts of seq which are known not to have changed
1271  auto cit2 = seq.begin();
1272  while (cit2!=cit) {
1273  s.push_back(*cit2);
1274  ++cit2;
1275  }
1276 
1277  // copy first changed element
1278  s.push_back(split_ex_to_pair(expanded_factor));
1279  ++cit2;
1280 
1281  // copy rest
1282  while (cit2!=last) {
1283  s.push_back(split_ex_to_pair(recombine_pair_to_ex(*cit2).expand(options)));
1284  ++cit2;
1285  }
1286  return s;
1287  }
1288  ++cit;
1289  }
1290 
1291  return epvector(); // nothing has changed
1292 }
1293 
1295 
1296 } // namespace GiNaC
Interface to GiNaC's sums of expressions.
Archiving of GiNaC expressions.
#define GINAC_ASSERT(X)
Assertion macro for checking invariances.
Definition: assertion.h:33
Sum of expressions.
Definition: add.h:32
expair combine_pair_with_coeff_to_pair(const expair &p, const ex &c) const override
Definition: add.cpp:550
This class is the ABC (abstract base class) of GiNaC's class hierarchy.
Definition: basic.h:105
ex diff(const symbol &s, unsigned nth=1) const
Default interface of nth derivative ex::diff(s, n).
Definition: basic.cpp:646
virtual bool has(const ex &other, unsigned options=0) const
Test for occurrence of a pattern.
Definition: basic.cpp:280
friend class ex
Definition: basic.h:108
unsigned flags
of type status_flags
Definition: basic.h:302
virtual void print(const print_context &c, unsigned level=0) const
Output to stream.
Definition: basic.cpp:116
ex subs_one_level(const exmap &m, unsigned options) const
Helper function for subs().
Definition: basic.cpp:585
const basic & hold() const
Stop further evaluation.
Definition: basic.cpp:887
const basic & setflag(unsigned f) const
Set some status_flags.
Definition: basic.h:288
virtual int compare_same_type(const basic &other) const
Returns order relation between two objects of same type.
Definition: basic.cpp:719
const basic & clearflag(unsigned f) const
Clear some status_flags.
Definition: basic.h:291
Wrapper template for making GiNaC classes out of STL containers.
Definition: container.h:73
ex op(size_t i) const override
Return operand/member at position i.
Definition: container.h:295
Lightweight wrapper for GiNaC's symbolic objects.
Definition: ex.h:72
bool match(const ex &pattern) const
Check whether expression matches a specified pattern.
Definition: ex.cpp:95
ex expand(unsigned options=0) const
Definition: ex.cpp:73
bool is_equal(const ex &other) const
Definition: ex.h:345
int degree(const ex &s) const
Definition: ex.h:173
ex evalf() const
Definition: ex.h:121
ex conjugate() const
Definition: ex.h:146
const_iterator end() const noexcept
Definition: ex.h:652
size_t nops() const
Definition: ex.h:135
ex imag_part() const
Definition: ex.h:148
ex subs(const exmap &m, unsigned options=0) const
Definition: ex.h:826
bool info(unsigned inf) const
Definition: ex.h:132
bool is_zero() const
Definition: ex.h:213
void print(const print_context &c, unsigned level=0) const
Print expression to stream.
Definition: ex.cpp:56
ex op(size_t i) const
Definition: ex.h:136
int ldegree(const ex &s) const
Definition: ex.h:174
ex real_part() const
Definition: ex.h:147
ex evalm() const
Definition: ex.h:122
ex coeff(const ex &s, int n=1) const
Definition: ex.h:175
A pair of expressions.
Definition: expair.h:38
void swap(expair &other)
Swap contents with other expair.
Definition: expair.h:82
ex rest
first member of pair, an arbitrary expression
Definition: expair.h:90
ex coeff
second member of pair, must be numeric
Definition: expair.h:91
bool is_equal(const expair &other) const
Member-wise check for canonical ordering equality.
Definition: expair.h:49
A sequence of class expair.
Definition: expairseq.h:50
size_t nops() const override
Number of operands/members.
epvector seq
Definition: expairseq.h:127
void construct_from_epvector(const epvector &v, bool do_index_renaming=false)
void construct_from_2_ex(const ex &lh, const ex &rh)
bool is_canonical() const
void construct_from_exvector(const exvector &v)
epvector evalchildren() const
ex op(size_t i) const override
Return operand/member at position i.
void do_print_tree(const print_tree &c, unsigned level) const
@ expand_rename_idx
used internally by mul::expand()
Definition: flags.h:34
@ algebraic
enable algebraic matching
Definition: flags.h:43
@ integer_polynomial
Definition: flags.h:256
@ cinteger_polynomial
Definition: flags.h:257
@ crational_polynomial
Definition: flags.h:259
@ rational_polynomial
Definition: flags.h:258
Symbolic matrices.
Definition: matrix.h:38
Product of expressions.
Definition: mul.h:32
ex thisexpairseq(const epvector &v, const ex &oc, bool do_index_renaming=false) const override
Definition: mul.cpp:936
bool info(unsigned inf) const override
Information about the object.
Definition: mul.cpp:272
ex real_part() const override
Definition: mul.cpp:608
bool expair_needs_further_processing(epp it) override
Definition: mul.cpp:1007
ex evalf() const override
Evaluate object numerically.
Definition: mul.cpp:577
epvector expandchildren(unsigned options) const
Member-wise expand the expairs representing this sequence.
Definition: mul.cpp:1258
unsigned precedence() const override
Return relative operator precedence (for parenthezing output).
Definition: mul.h:51
bool is_polynomial(const ex &var) const override
Check whether this is a polynomial in the given variables.
Definition: mul.cpp:386
return_type_t return_type_tinfo() const override
Definition: mul.cpp:922
ex default_overall_coeff() const override
Definition: mul.cpp:1030
void do_print_csrc(const print_csrc &c, unsigned level) const
Definition: mul.cpp:208
unsigned return_type() const override
Definition: mul.cpp:889
void do_print(const print_context &c, unsigned level) const
Definition: mul.cpp:148
void do_print_python_repr(const print_python_repr &c, unsigned level) const
Definition: mul.cpp:261
ex conjugate() const override
Definition: mul.cpp:829
bool can_make_flat(const expair &p) const override
Definition: mul.cpp:1050
ex imag_part() const override
Definition: mul.cpp:615
expair combine_ex_with_coeff_to_pair(const ex &e, const ex &c) const override
Definition: mul.cpp:956
void combine_overall_coeff(const ex &c) override
Definition: mul.cpp:1035
int ldegree(const ex &s) const override
Return degree of lowest power in object s.
Definition: mul.cpp:412
ex eval() const override
Perform automatic term rewriting rules in this class.
Definition: mul.cpp:468
expair split_ex_to_pair(const ex &e) const override
Definition: mul.cpp:946
ex expand(unsigned options=0) const override
Expand expression, i.e.
Definition: mul.cpp:1072
int degree(const ex &s) const override
Return degree of highest power in object s.
Definition: mul.cpp:397
void do_print_latex(const print_latex &c, unsigned level) const
Definition: mul.cpp:168
static bool can_be_further_expanded(const ex &e)
Definition: mul.cpp:1058
ex derivative(const symbol &s) const override
Implementation of ex::diff() for a product.
Definition: mul.cpp:863
void find_real_imag(ex &, ex &) const
Definition: mul.cpp:587
ex coeff(const ex &s, int n=1) const override
Return coefficient of degree n in object s.
Definition: mul.cpp:427
friend class power
Definition: mul.h:37
ex recombine_pair_to_ex(const expair &p) const override
Definition: mul.cpp:999
ex evalm() const override
Evaluate sums, products and integer powers of matrices.
Definition: mul.cpp:622
void print_overall_coeff(const print_context &c, const char *mul_sym) const
Definition: mul.cpp:126
expair combine_pair_with_coeff_to_pair(const expair &p, const ex &c) const override
Definition: mul.cpp:976
ex algebraic_subs_mul(const exmap &m, unsigned options) const
Definition: mul.cpp:770
ex eval_ncmul(const exvector &v) const override
Definition: mul.cpp:660
bool has(const ex &other, unsigned options=0) const override
Test for occurrence of a pattern.
Definition: mul.cpp:754
mul(const ex &lh, const ex &rh)
Definition: mul.cpp:64
This class is a wrapper around CLN-numbers within the GiNaC class hierarchy.
Definition: numeric.h:82
bool is_pos_integer() const
True if object is an exact integer greater than zero.
Definition: numeric.cpp:1161
bool is_integer() const
True if object is a non-complex integer.
Definition: numeric.cpp:1154
const numeric mul(const numeric &other) const
Numerical multiplication method.
Definition: numeric.cpp:880
const numeric div(const numeric &other) const
Numerical division method.
Definition: numeric.cpp:890
This class holds a two-component object, a basis and and exponent representing exponentiation.
Definition: power.h:39
ex basis
Definition: power.h:105
ex exponent
Definition: power.h:106
Base class for print_contexts.
Definition: print.h:103
Base context for C source output.
Definition: print.h:158
Context for latex-parsable output.
Definition: print.h:123
Context for python-parsable output.
Definition: print.h:139
@ noncommutative_composite
Definition: flags.h:282
@ expanded
.expand(0) has already done its job (other expand() options ignore this flag)
Definition: flags.h:204
@ evaluated
.eval() has already done its job
Definition: flags.h:203
@ hash_calculated
.calchash() has already done its job
Definition: flags.h:205
@ no_pattern
disable pattern matching
Definition: flags.h:51
@ algebraic
enable algebraic substitutions
Definition: flags.h:53
Basic CAS symbol.
Definition: symbol.h:39
Definition of optimizing macros.
#define likely(cond)
Definition: compiler.h:32
#define unlikely(cond)
Definition: compiler.h:31
upvec factors
Definition: factor.cpp:1461
unsigned options
Definition: factor.cpp:2480
ex x
Definition: factor.cpp:1641
size_t n
Definition: factor.cpp:1463
size_t c
Definition: factor.cpp:770
mvec m
Definition: factor.cpp:771
size_t last
Definition: factor.cpp:1465
Interface to GiNaC's indexed expressions.
Definition of GiNaC's lst.
Interface to symbolic matrices.
Interface to GiNaC's products of expressions.
Definition: add.cpp:38
const numeric * _num_1_p
Definition: utils.cpp:351
const numeric pow(const numeric &x, const numeric &y)
Definition: numeric.h:251
std::map< ex, ex, ex_is_less > exmap
Definition: basic.h:50
std::vector< expair > epvector
expair-vector
Definition: expairseq.h:33
const ex _ex1
Definition: utils.cpp:385
bool are_ex_trivially_equal(const ex &e1, const ex &e2)
Compare two objects of class quickly without doing a deep tree traversal.
Definition: ex.h:684
const ex _ex_1
Definition: utils.cpp:352
bool algebraic_match_mul_with_mul(const mul &e, const ex &pat, exmap &repls, int factor, int &nummatches, const std::vector< bool > &subsed, std::vector< bool > &matched)
Checks whether e matches to the pattern pat and the (possibly to be updated) list of replacements rep...
Definition: mul.cpp:723
print_func< print_context >(&varidx::do_print). print_func< print_latex >(&varidx
Definition: idx.cpp:45
GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(add, expairseq, print_func< print_context >(&add::do_print). print_func< print_latex >(&add::do_print_latex). print_func< print_csrc >(&add::do_print_csrc). print_func< print_tree >(&add::do_print_tree). print_func< print_python_repr >(&add::do_print_python_repr)) add
Definition: add.cpp:40
GINAC_IMPLEMENT_REGISTERED_CLASS_OPT_T(lst, basic, print_func< print_context >(&lst::do_print). print_func< print_tree >(&lst::do_print_tree)) template<> bool lst GINAC_BIND_UNARCHIVER(lst)
Specialization of container::info() for lst.
Definition: lst.cpp:42
const numeric * _num1_p
Definition: utils.cpp:384
epvector::iterator epp
expair-vector pointer
Definition: expairseq.h:34
ex factor(const ex &poly, unsigned options)
Interface function to the outside world.
Definition: factor.cpp:2581
lst rename_dummy_indices_uniquely(const exvector &va, const exvector &vb)
Similar to above, where va and vb are the same and the return value is a list of two lists for substi...
Definition: indexed.cpp:1460
const ex _ex0
Definition: utils.cpp:369
bool tryfactsubs(const ex &origfactor, const ex &patternfactor, int &nummatches, exmap &repls)
Definition: mul.cpp:672
std::vector< ex > exvector
Definition: basic.h:46
const numeric * _num0_p
Definition: utils.cpp:367
exvector get_all_dummy_indices_safely(const ex &e)
More reliable version of the form.
Definition: indexed.cpp:1394
Interface to GiNaC's overloaded operators.
Interface to GiNaC's symbolic exponentiation (basis^exponent).
To distinguish between different kinds of non-commutative objects.
Definition: registrar.h:44
Interface to GiNaC's symbolic objects.
Interface to several small and furry utilities needed within GiNaC but not of any interest to the use...

This page is part of the GiNaC developer's reference. It was generated automatically by doxygen. For an introduction, see the tutorial.