GiNaC  1.7.7
mul.cpp
Go to the documentation of this file.
1 
5 /*
6  * GiNaC Copyright (C) 1999-2019 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) {
275  case info_flags::polynomial:
276  case info_flags::integer_polynomial:
277  case info_flags::cinteger_polynomial:
278  case info_flags::rational_polynomial:
279  case info_flags::real:
280  case info_flags::rational:
281  case info_flags::integer:
282  case info_flags::crational:
283  case info_flags::cinteger:
284  case info_flags::even:
285  case info_flags::crational_polynomial:
286  case info_flags::rational_function: {
287  for (auto & it : seq) {
288  if (!recombine_pair_to_ex(it).info(inf))
289  return false;
290  }
291  if (overall_coeff.is_equal(*_num1_p) && inf == info_flags::even)
292  return true;
293  return overall_coeff.info(inf);
294  }
295  case info_flags::positive:
296  case info_flags::negative: {
297  if ((inf==info_flags::positive) && (flags & status_flags::is_positive))
298  return true;
299  else if ((inf==info_flags::negative) && (flags & status_flags::is_negative))
300  return true;
301  if (flags & status_flags::purely_indefinite)
302  return false;
303 
304  bool pos = true;
305  for (auto & it : seq) {
306  const ex& factor = recombine_pair_to_ex(it);
307  if (factor.info(info_flags::positive))
308  continue;
309  else if (factor.info(info_flags::negative))
310  pos = !pos;
311  else
312  return false;
313  }
314  if (overall_coeff.info(info_flags::negative))
315  pos = !pos;
317  return (inf == info_flags::positive? pos : !pos);
318  }
319  case info_flags::nonnegative: {
320  if (flags & status_flags::is_positive)
321  return true;
322  bool pos = true;
323  for (auto & it : seq) {
324  const ex& factor = recombine_pair_to_ex(it);
325  if (factor.info(info_flags::nonnegative) || factor.info(info_flags::positive))
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);
339  if (factor.info(info_flags::posint))
340  continue;
341  else if (factor.info(info_flags::negint))
342  pos = !pos;
343  else
344  return false;
345  }
346  if (overall_coeff.info(info_flags::negint))
347  pos = !pos;
348  else if (!overall_coeff.info(info_flags::posint))
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);
356  if (factor.info(info_flags::nonnegint) || factor.info(info_flags::posint))
357  continue;
358  else if (factor.info(info_flags::negint))
359  pos = !pos;
360  else
361  return false;
362  }
363  if (overall_coeff.info(info_flags::negint))
364  pos = !pos;
365  else if (!overall_coeff.info(info_flags::posint))
366  return false;
367  return pos;
368  }
369  case info_flags::indefinite: {
370  if (flags & status_flags::purely_indefinite)
371  return true;
373  return false;
374  for (auto & it : seq) {
375  const ex& term = recombine_pair_to_ex(it);
376  if (term.info(info_flags::positive) || term.info(info_flags::negative))
377  return false;
378  }
379  setflag(status_flags::purely_indefinite);
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 {
470  if (flags & status_flags::evaluated) {
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);
555  primitive.clearflag(status_flags::hash_calculated);
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) {
592  ex factor = recombine_pair_to_ex(it);
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 {
756  if(!(options & has_options::algebraic))
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)
824  return subs_one_level(m, options | subs_options::algebraic);
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  }
851  ex x = overall_coeff.conjugate();
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
893  return return_types::commutative;
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();
902  if (rt == return_types::noncommutative_composite)
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
913  return return_types::noncommutative_composite;
914  }
915  }
916  ++i;
917  }
918  // all factors checked
919  return all_commutative ? return_types::commutative : return_types::noncommutative;
920 }
921 
922 return_type_t mul::return_type_tinfo() const
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 
946 expair mul::split_ex_to_pair(const ex & e) const
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 
956 expair mul::combine_ex_with_coeff_to_pair(const ex & e,
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 
976 expair mul::combine_pair_with_coeff_to_pair(const expair & p,
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)
996  return split_ex_to_pair(pow(recombine_pair_to_ex(p),c));
997 }
998 
999 ex mul::recombine_pair_to_ex(const expair & p) const
1000 {
1001  if (p.coeff.is_equal(_ex1))
1002  return p.rest;
1003  else
1004  return dynallocate<power>(p.rest, p.coeff);
1005 }
1006 
1007 bool mul::expair_needs_further_processing(epp it)
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
1012  *it = split_ex_to_pair(recombine_pair_to_ex(*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  }
1020  expair ep = split_ex_to_pair(recombine_pair_to_ex(*it));
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 
1030 ex mul::default_overall_coeff() const
1031 {
1032  return _ex1;
1033 }
1034 
1035 void mul::combine_overall_coeff(const ex & c)
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 
1058 bool mul::can_be_further_expanded(const ex & e)
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) {
1083  setflag(status_flags::expanded);
1084  return *this;
1085  }
1086 
1087  // do not rename indices if the object has no indices at all
1088  if ((!(options & expand_options::expand_rename_idx)) &&
1089  this->info(info_flags::has_indices))
1090  options |= expand_options::expand_rename_idx;
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 
1258 epvector mul::expandchildren(unsigned options) const
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
GiNaC::mul::do_print
void do_print(const print_context &c, unsigned level) const
Definition: mul.cpp:148
GiNaC::print_python_repr
Context for python-parsable output.
Definition: print.h:138
GiNaC::epvector
std::vector< expair > epvector
expair-vector
Definition: expairseq.h:33
GiNaC::ex::expand
ex expand(unsigned options=0) const
Definition: ex.cpp:73
GiNaC::mul::do_print_csrc
void do_print_csrc(const print_csrc &c, unsigned level) const
Definition: mul.cpp:208
GiNaC::real_part
ex real_part(const ex &thisex)
Definition: ex.h:705
GiNaC::GINAC_IMPLEMENT_REGISTERED_CLASS_OPT
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::numeric::is_integer
bool is_integer() const
True if object is a non-complex integer.
Definition: numeric.cpp:1147
GiNaC::numeric::mul
const numeric mul(const numeric &other) const
Numerical multiplication method.
Definition: numeric.cpp:873
GiNaC::add::combine_pair_with_coeff_to_pair
expair combine_pair_with_coeff_to_pair(const expair &p, const ex &c) const override
Definition: add.cpp:550
GiNaC::mul::do_print_latex
void do_print_latex(const print_latex &c, unsigned level) const
Definition: mul.cpp:168
GiNaC::expairseq::is_canonical
bool is_canonical() const
mul.h
GiNaC::numeric::info
bool info(unsigned inf) const override
Information about the object.
Definition: numeric.cpp:677
GiNaC::expairseq::do_print_tree
void do_print_tree(const print_tree &c, unsigned level) const
GiNaC::expair::is_equal
bool is_equal(const expair &other) const
Member-wise check for canonical ordering equality.
Definition: expair.h:49
GiNaC::expairseq::nops
size_t nops() const override
Number of operands/members.
GiNaC::ex::coeff
ex coeff(const ex &s, int n=1) const
Definition: ex.h:173
GiNaC::mul::do_print_python_repr
void do_print_python_repr(const print_python_repr &c, unsigned level) const
Definition: mul.cpp:261
GiNaC::_ex0
const ex _ex0
Definition: utils.cpp:177
GiNaC::rename_dummy_indices_uniquely
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
GiNaC::ex::subs
ex subs(const exmap &m, unsigned options=0) const
Definition: ex.h:810
GiNaC::print_context
Base class for print_contexts.
Definition: print.h:102
add.h
GiNaC::print_csrc
Base context for C source output.
Definition: print.h:157
GiNaC::evalf
ex evalf(const ex &thisex)
Definition: ex.h:753
power.h
GiNaC::exvector
std::vector< ex > exvector
Definition: basic.h:46
GiNaC::ex::nops
size_t nops() const
Definition: ex.h:133
GiNaC::power
This class holds a two-component object, a basis and and exponent representing exponentiation.
Definition: power.h:38
GiNaC::expairseq::construct_from_epvector
void construct_from_epvector(const epvector &v, bool do_index_renaming=false)
GiNaC::basic::diff
ex diff(const symbol &s, unsigned nth=1) const
Default interface of nth derivative ex::diff(s, n).
Definition: basic.cpp:646
GiNaC::power::exponent
ex exponent
Definition: power.h:106
GiNaC::_ex1
const ex _ex1
Definition: utils.cpp:193
GiNaC::has
bool has(const ex &thisex, const ex &pattern, unsigned options=0)
Definition: ex.h:711
options
unsigned options
Definition: factor.cpp:2478
GiNaC::ex::is_equal
bool is_equal(const ex &other) const
Definition: ex.h:329
factors
upvec factors
Definition: factor.cpp:1461
m
mvec m
Definition: factor.cpp:771
GiNaC::add
Sum of expressions.
Definition: add.h:31
GiNaC
Definition: add.cpp:38
GiNaC::conjugate
ex conjugate(const ex &thisex)
Definition: ex.h:702
GiNaC::ex::eval_ncmul
ex eval_ncmul(const exvector &v) const
Definition: ex.h:121
GiNaC::mul::mul
mul(const ex &lh, const ex &rh)
Definition: mul.cpp:64
GiNaC::expairseq::construct_from_2_ex
void construct_from_2_ex(const ex &lh, const ex &rh)
GiNaC::epp
epvector::iterator epp
expair-vector pointer
Definition: expairseq.h:34
GiNaC::basic::clearflag
const basic & clearflag(unsigned f) const
Clear some status_flags.
Definition: basic.h:291
GiNaC::are_ex_trivially_equal
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:668
matrix.h
x
ex x
Definition: factor.cpp:1638
GiNaC::ex::op
ex op(size_t i) const
Definition: ex.h:134
GiNaC::ex::info
bool info(unsigned inf) const
Definition: ex.h:130
utils.h
GiNaC::ex::match
bool match(const ex &pattern) const
Check whether expression matches a specified pattern.
Definition: ex.cpp:95
last
size_t last
Definition: factor.cpp:1465
GiNaC::expair::swap
void swap(expair &other)
Swap contents with other expair.
Definition: expair.h:82
GiNaC::expair::coeff
ex coeff
second member of pair, must be numeric
Definition: expair.h:91
GiNaC::ex
Lightweight wrapper for GiNaC's symbolic objects.
Definition: ex.h:72
lst.h
GiNaC::ex::begin
const_iterator begin() const noexcept
Definition: ex.h:631
GINAC_BIND_UNARCHIVER
#define GINAC_BIND_UNARCHIVER(classname)
Definition: archive.h:230
GiNaC::ex::imag_part
ex imag_part() const
Definition: ex.h:146
GiNaC::numeric::is_pos_integer
bool is_pos_integer() const
True if object is an exact integer greater than zero.
Definition: numeric.cpp:1154
GiNaC::expand
ex expand(const ex &thisex, unsigned options=0)
Definition: ex.h:699
GiNaC::expairseq::seq
epvector seq
Definition: expairseq.h:127
GiNaC::mul::precedence
unsigned precedence() const override
Return relative operator precedence (for parenthezing output).
Definition: mul.h:51
GiNaC::print_latex
Context for latex-parsable output.
Definition: print.h:122
symbol.h
GiNaC::container::op
ex op(size_t i) const override
Return operand/member at position i.
Definition: container.h:461
compiler.h
GiNaC::ex::print
void print(const print_context &c, unsigned level=0) const
Print expression to stream.
Definition: ex.cpp:56
GiNaC::eval
ex eval(const ex &thisex)
Definition: ex.h:750
GiNaC::expair::rest
ex rest
first member of pair, an arbitrary expression
Definition: expair.h:90
GiNaC::ex::real_part
ex real_part() const
Definition: ex.h:145
GiNaC::return_type_t
To distinguish between different kinds of non-commutative objects.
Definition: registrar.h:43
unlikely
#define unlikely(cond)
Definition: compiler.h:31
GiNaC::ldegree
int ldegree(const ex &thisex, const ex &s)
Definition: ex.h:723
GiNaC::op
ex op(const ex &thisex, size_t i)
Definition: ex.h:795
GiNaC::_num_1_p
const numeric * _num_1_p
Definition: utils.cpp:159
GiNaC::container
Wrapper template for making GiNaC classes out of STL containers.
Definition: container.h:130
GiNaC::tryfactsubs
bool tryfactsubs(const ex &origfactor, const ex &patternfactor, int &nummatches, exmap &repls)
Definition: mul.cpp:672
c
size_t c
Definition: factor.cpp:770
GiNaC::exmap
std::map< ex, ex, ex_is_less > exmap
Definition: basic.h:50
GiNaC::imag_part
ex imag_part(const ex &thisex)
Definition: ex.h:708
GiNaC::real
const numeric real(const numeric &x)
Definition: numeric.h:309
GiNaC::coeff
ex coeff(const ex &thisex, const ex &s, int n=1)
Definition: ex.h:726
GiNaC::factor
ex factor(const ex &poly, unsigned options)
Interface function to the outside world.
Definition: factor.cpp:2579
GiNaC::expairseq::overall_coeff
ex overall_coeff
Definition: expairseq.h:128
GiNaC::degree
int degree(const ex &thisex, const ex &s)
Definition: ex.h:720
archive.h
GiNaC::symbol
Basic CAS symbol.
Definition: symbol.h:38
n
size_t n
Definition: factor.cpp:1463
GiNaC::expairseq::construct_from_exvector
void construct_from_exvector(const exvector &v)
GiNaC::pow
const numeric pow(const numeric &x, const numeric &y)
Definition: numeric.h:249
GiNaC::to_int
int to_int(const numeric &x)
Definition: numeric.h:300
GiNaC::matrix
Symbolic matrices.
Definition: matrix.h:95
GiNaC::mul::coeff
ex coeff(const ex &s, int n=1) const override
Return coefficient of degree n in object s.
Definition: mul.cpp:427
GiNaC::is_polynomial
bool is_polynomial(const ex &thisex, const ex &vars)
Definition: ex.h:717
GiNaC::basic
This class is the ABC (abstract base class) of GiNaC's class hierarchy.
Definition: basic.h:104
GiNaC::is_negative
bool is_negative(const numeric &x)
Definition: numeric.h:267
GiNaC::expair
A pair of expressions.
Definition: expair.h:37
GiNaC::_num0_p
const numeric * _num0_p
Definition: utils.cpp:175
GiNaC::info_flags::negint
Definition: flags.h:230
GiNaC::mul::print_overall_coeff
void print_overall_coeff(const print_context &c, const char *mul_sym) const
Definition: mul.cpp:126
GiNaC::power::basis
ex basis
Definition: power.h:105
GiNaC::ex::is_zero
bool is_zero() const
Definition: ex.h:211
GiNaC::expairseq::op
ex op(size_t i) const override
Return operand/member at position i.
GiNaC::algebraic_match_mul_with_mul
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
indexed.h
GiNaC::mul::recombine_pair_to_ex
ex recombine_pair_to_ex(const expair &p) const override
Definition: mul.cpp:999
GiNaC::evalm
ex evalm(const ex &thisex)
Definition: ex.h:756
GiNaC::nops
size_t nops(const ex &thisex)
Definition: ex.h:696
GiNaC::is_positive
bool is_positive(const numeric &x)
Definition: numeric.h:264
GiNaC::_num1_p
const numeric * _num1_p
Definition: utils.cpp:192
GiNaC::print_func< print_context >
print_func< print_context >(&varidx::do_print). print_func< print_latex >(&varidx
Definition: idx.cpp:45
operators.h
GiNaC::_ex_1
const ex _ex_1
Definition: utils.cpp:160
GiNaC::numeric
This class is a wrapper around CLN-numbers within the GiNaC class hierarchy.
Definition: numeric.h:81
GiNaC::get_all_dummy_indices_safely
exvector get_all_dummy_indices_safely(const ex &e)
More reliable version of the form.
Definition: indexed.cpp:1394
GINAC_ASSERT
#define GINAC_ASSERT(X)
Assertion macro for checking invariances.
Definition: assertion.h:33
GiNaC::expairseq
A sequence of class expair.
Definition: expairseq.h:49
GiNaC::ex_is_less
Definition: ex.h:674
GiNaC::mul
Product of expressions.
Definition: mul.h:31
likely
#define likely(cond)
Definition: compiler.h:32

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