/[GiNaC]/ginac/add.cpp
ViewVC logotype

Contents of /ginac/add.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.14 - (hide annotations)
Fri Jan 21 15:20:30 2000 UTC (13 years, 4 months ago) by cbauer
Branch: MAIN
Changes since 1.13: +26 -26 lines
- changed all instances of "foo const &/*" to "const foo &/*"
- changed function arguments like "int const" to a simple "int"

1 cbauer 1.1 /** @file add.cpp
2     *
3 cbauer 1.4 * Implementation of GiNaC's sums of expressions. */
4    
5     /*
6 kreckel 1.12 * GiNaC Copyright (C) 1999-2000 Johannes Gutenberg University Mainz, Germany
7 cbauer 1.2 *
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21     */
22 cbauer 1.1
23     #include <iostream>
24     #include <stdexcept>
25    
26 cbauer 1.3 #include "add.h"
27     #include "mul.h"
28 cbauer 1.13 #include "archive.h"
29 cbauer 1.5 #include "debugmsg.h"
30 kreckel 1.10 #include "utils.h"
31 cbauer 1.5
32 frink 1.7 #ifndef NO_GINAC_NAMESPACE
33 cbauer 1.5 namespace GiNaC {
34 frink 1.7 #endif // ndef NO_GINAC_NAMESPACE
35 cbauer 1.1
36 cbauer 1.13 GINAC_IMPLEMENT_REGISTERED_CLASS(add, expairseq)
37    
38 cbauer 1.1 //////////
39     // default constructor, destructor, copy constructor assignment operator and helpers
40     //////////
41    
42     // public
43    
44     add::add()
45     {
46     debugmsg("add default constructor",LOGLEVEL_CONSTRUCT);
47 cbauer 1.3 tinfo_key = TINFO_add;
48 cbauer 1.1 }
49    
50     add::~add()
51     {
52     debugmsg("add destructor",LOGLEVEL_DESTRUCT);
53     destroy(0);
54     }
55    
56 cbauer 1.14 add::add(const add & other)
57 cbauer 1.1 {
58     debugmsg("add copy constructor",LOGLEVEL_CONSTRUCT);
59     copy(other);
60     }
61    
62 cbauer 1.14 const add & add::operator=(const add & other)
63 cbauer 1.1 {
64     debugmsg("add operator=",LOGLEVEL_ASSIGNMENT);
65     if (this != &other) {
66     destroy(1);
67     copy(other);
68     }
69     return *this;
70     }
71    
72     // protected
73    
74 cbauer 1.14 void add::copy(const add & other)
75 cbauer 1.1 {
76 cbauer 1.13 inherited::copy(other);
77 cbauer 1.1 }
78    
79     void add::destroy(bool call_parent)
80     {
81 cbauer 1.13 if (call_parent) inherited::destroy(call_parent);
82 cbauer 1.1 }
83    
84     //////////
85     // other constructors
86     //////////
87    
88     // public
89    
90 cbauer 1.14 add::add(const ex & lh, const ex & rh)
91 cbauer 1.1 {
92     debugmsg("add constructor from ex,ex",LOGLEVEL_CONSTRUCT);
93 cbauer 1.3 tinfo_key = TINFO_add;
94 kreckel 1.10 overall_coeff=_ex0();
95 cbauer 1.1 construct_from_2_ex(lh,rh);
96 cbauer 1.6 GINAC_ASSERT(is_canonical());
97 cbauer 1.1 }
98    
99 cbauer 1.14 add::add(const exvector & v)
100 cbauer 1.1 {
101     debugmsg("add constructor from exvector",LOGLEVEL_CONSTRUCT);
102 cbauer 1.3 tinfo_key = TINFO_add;
103 kreckel 1.10 overall_coeff=_ex0();
104 cbauer 1.1 construct_from_exvector(v);
105 cbauer 1.6 GINAC_ASSERT(is_canonical());
106 cbauer 1.1 }
107    
108     /*
109 cbauer 1.14 add::add(const epvector & v, bool do_not_canonicalize)
110 cbauer 1.1 {
111     debugmsg("add constructor from epvector,bool",LOGLEVEL_CONSTRUCT);
112 cbauer 1.3 tinfo_key = TINFO_add;
113 cbauer 1.1 if (do_not_canonicalize) {
114     seq=v;
115     #ifdef EXPAIRSEQ_USE_HASHTAB
116     combine_same_terms(); // to build hashtab
117     #endif // def EXPAIRSEQ_USE_HASHTAB
118     } else {
119     construct_from_epvector(v);
120     }
121 cbauer 1.6 GINAC_ASSERT(is_canonical());
122 cbauer 1.1 }
123     */
124    
125 cbauer 1.14 add::add(const epvector & v)
126 cbauer 1.1 {
127     debugmsg("add constructor from epvector",LOGLEVEL_CONSTRUCT);
128 cbauer 1.3 tinfo_key = TINFO_add;
129 kreckel 1.10 overall_coeff=_ex0();
130 cbauer 1.1 construct_from_epvector(v);
131 cbauer 1.6 GINAC_ASSERT(is_canonical());
132 cbauer 1.1 }
133    
134 cbauer 1.14 add::add(const epvector & v, const ex & oc)
135 cbauer 1.1 {
136     debugmsg("add constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
137 cbauer 1.3 tinfo_key = TINFO_add;
138 cbauer 1.1 overall_coeff=oc;
139     construct_from_epvector(v);
140 cbauer 1.6 GINAC_ASSERT(is_canonical());
141 cbauer 1.1 }
142    
143 cbauer 1.14 add::add(epvector * vp, const ex & oc)
144 cbauer 1.1 {
145     debugmsg("add constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
146 cbauer 1.3 tinfo_key = TINFO_add;
147 cbauer 1.6 GINAC_ASSERT(vp!=0);
148 cbauer 1.1 overall_coeff=oc;
149     construct_from_epvector(*vp);
150     delete vp;
151 cbauer 1.6 GINAC_ASSERT(is_canonical());
152 cbauer 1.1 }
153    
154     //////////
155 cbauer 1.13 // archiving
156     //////////
157    
158     /** Construct object from archive_node. */
159     add::add(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
160     {
161     debugmsg("add constructor from archive_node", LOGLEVEL_CONSTRUCT);
162     }
163    
164     /** Unarchive the object. */
165     ex add::unarchive(const archive_node &n, const lst &sym_lst)
166     {
167     return (new add(n, sym_lst))->setflag(status_flags::dynallocated);
168     }
169    
170     /** Archive the object. */
171     void add::archive(archive_node &n) const
172     {
173     inherited::archive(n);
174     }
175    
176     //////////
177 cbauer 1.1 // functions overriding virtual functions from bases classes
178     //////////
179    
180     // public
181    
182     basic * add::duplicate() const
183     {
184     debugmsg("add duplicate",LOGLEVEL_DUPLICATE);
185     return new add(*this);
186     }
187    
188 kreckel 1.11 /*void add::print(ostream & os, unsigned upper_precedence) const
189 kreckel 1.9 {
190     debugmsg("add print",LOGLEVEL_PRINT);
191     if (precedence<=upper_precedence) os << "(";
192     numeric coeff;
193     bool first=true;
194     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
195     coeff = ex_to_numeric(cit->coeff);
196     if (!first) {
197     if (coeff.csgn()==-1) os << '-'; else os << '+';
198     } else {
199     if (coeff.csgn()==-1) os << '-';
200     first=false;
201     }
202 kreckel 1.10 if (!coeff.is_equal(_num1()) &&
203     !coeff.is_equal(_num_1())) {
204 kreckel 1.11 if (coeff.is_rational()) {
205     if (coeff.is_negative())
206     os << -coeff;
207     else
208     os << coeff;
209     } else {
210     if (coeff.csgn()==-1)
211     (-coeff).print(os, precedence);
212     else
213     coeff.print(os, precedence);
214     }
215 kreckel 1.9 os << '*';
216     }
217     os << cit->rest;
218     }
219     // print the overall numeric coefficient, if present:
220     if (!overall_coeff.is_zero()) {
221     if (overall_coeff.info(info_flags::positive)) os << '+';
222     os << overall_coeff;
223 kreckel 1.11 }
224     if (precedence<=upper_precedence) os << ")";
225     }*/
226    
227     void add::print(ostream & os, unsigned upper_precedence) const
228     {
229     debugmsg("add print",LOGLEVEL_PRINT);
230     if (precedence<=upper_precedence) os << "(";
231     numeric coeff;
232     bool first = true;
233     // first print the overall numeric coefficient, if present:
234     if (!overall_coeff.is_zero()) {
235     os << overall_coeff;
236     first = false;
237     }
238     // then proceed with the remaining factors:
239     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
240     coeff = ex_to_numeric(cit->coeff);
241     if (!first) {
242     if (coeff.csgn()==-1) os << '-'; else os << '+';
243     } else {
244     if (coeff.csgn()==-1) os << '-';
245     first = false;
246     }
247     if (!coeff.is_equal(_num1()) &&
248     !coeff.is_equal(_num_1())) {
249     if (coeff.is_rational()) {
250     if (coeff.is_negative())
251     os << -coeff;
252     else
253     os << coeff;
254     } else {
255     if (coeff.csgn()==-1)
256     (-coeff).print(os, precedence);
257     else
258     coeff.print(os, precedence);
259     }
260     os << '*';
261     }
262     os << cit->rest;
263 kreckel 1.9 }
264     if (precedence<=upper_precedence) os << ")";
265     }
266    
267     void add::printraw(ostream & os) const
268     {
269     debugmsg("add printraw",LOGLEVEL_PRINT);
270    
271     os << "+(";
272     for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
273     os << "(";
274     (*it).rest.bp->printraw(os);
275     os << ",";
276     (*it).coeff.bp->printraw(os);
277     os << "),";
278     }
279     os << ",hash=" << hashvalue << ",flags=" << flags;
280     os << ")";
281     }
282    
283     void add::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
284     {
285     debugmsg("add print csrc", LOGLEVEL_PRINT);
286     if (precedence <= upper_precedence)
287     os << "(";
288    
289     // Print arguments, separated by "+"
290     epvector::const_iterator it = seq.begin();
291     epvector::const_iterator itend = seq.end();
292     while (it != itend) {
293    
294     // If the coefficient is -1, it is replaced by a single minus sign
295 kreckel 1.10 if (it->coeff.compare(_num1()) == 0) {
296 kreckel 1.9 it->rest.bp->printcsrc(os, type, precedence);
297 kreckel 1.10 } else if (it->coeff.compare(_num_1()) == 0) {
298 kreckel 1.9 os << "-";
299     it->rest.bp->printcsrc(os, type, precedence);
300 kreckel 1.10 } else if (ex_to_numeric(it->coeff).numer().compare(_num1()) == 0) {
301 kreckel 1.9 it->rest.bp->printcsrc(os, type, precedence);
302     os << "/";
303     ex_to_numeric(it->coeff).denom().printcsrc(os, type, precedence);
304 kreckel 1.10 } else if (ex_to_numeric(it->coeff).numer().compare(_num_1()) == 0) {
305 kreckel 1.9 os << "-";
306     it->rest.bp->printcsrc(os, type, precedence);
307     os << "/";
308     ex_to_numeric(it->coeff).denom().printcsrc(os, type, precedence);
309     } else {
310     it->coeff.bp->printcsrc(os, type, precedence);
311     os << "*";
312     it->rest.bp->printcsrc(os, type, precedence);
313     }
314    
315     // Separator is "+", except if the following expression would have a leading minus sign
316     it++;
317 kreckel 1.10 if (it != itend && !(it->coeff.compare(_num0()) < 0 || (it->coeff.compare(_num1()) == 0 && is_ex_exactly_of_type(it->rest, numeric) && it->rest.compare(_num0()) < 0)))
318 kreckel 1.9 os << "+";
319     }
320    
321 kreckel 1.10 if (!overall_coeff.is_equal(_ex0())) {
322 kreckel 1.9 if (overall_coeff.info(info_flags::positive)) os << '+';
323     overall_coeff.bp->printcsrc(os,type,precedence);
324     }
325    
326     if (precedence <= upper_precedence)
327     os << ")";
328     }
329    
330 cbauer 1.1 bool add::info(unsigned inf) const
331     {
332     // TODO: optimize
333 kreckel 1.9 if (inf==info_flags::polynomial ||
334     inf==info_flags::integer_polynomial ||
335     inf==info_flags::cinteger_polynomial ||
336     inf==info_flags::rational_polynomial ||
337     inf==info_flags::crational_polynomial ||
338     inf==info_flags::rational_function) {
339 cbauer 1.1 for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
340     if (!(recombine_pair_to_ex(*it).info(inf)))
341     return false;
342     }
343 kreckel 1.9 return overall_coeff.info(inf);
344 cbauer 1.1 } else {
345 cbauer 1.13 return inherited::info(inf);
346 cbauer 1.1 }
347     }
348    
349 cbauer 1.14 int add::degree(const symbol & s) const
350 cbauer 1.1 {
351     int deg=INT_MIN;
352 kreckel 1.10 if (!overall_coeff.is_equal(_ex0())) {
353 cbauer 1.1 deg=0;
354     }
355     int cur_deg;
356     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
357     cur_deg=(*cit).rest.degree(s);
358     if (cur_deg>deg) deg=cur_deg;
359     }
360     return deg;
361     }
362    
363 cbauer 1.14 int add::ldegree(const symbol & s) const
364 cbauer 1.1 {
365     int deg=INT_MAX;
366 kreckel 1.10 if (!overall_coeff.is_equal(_ex0())) {
367 cbauer 1.1 deg=0;
368     }
369     int cur_deg;
370     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
371     cur_deg=(*cit).rest.ldegree(s);
372     if (cur_deg<deg) deg=cur_deg;
373     }
374     return deg;
375     }
376    
377 cbauer 1.14 ex add::coeff(const symbol & s, int n) const
378 cbauer 1.1 {
379     epvector coeffseq;
380     coeffseq.reserve(seq.size());
381    
382     epvector::const_iterator it=seq.begin();
383     while (it!=seq.end()) {
384     coeffseq.push_back(combine_ex_with_coeff_to_pair((*it).rest.coeff(s,n),
385     (*it).coeff));
386     ++it;
387     }
388     if (n==0) {
389     return (new add(coeffseq,overall_coeff))->setflag(status_flags::dynallocated);
390     }
391     return (new add(coeffseq))->setflag(status_flags::dynallocated);
392     }
393    
394     ex add::eval(int level) const
395     {
396     // simplifications: +(;c) -> c
397     // +(x;1) -> x
398    
399     debugmsg("add eval",LOGLEVEL_MEMBER_FUNCTION);
400    
401     epvector * evaled_seqp=evalchildren(level);
402     if (evaled_seqp!=0) {
403     // do more evaluation later
404     return (new add(evaled_seqp,overall_coeff))->
405     setflag(status_flags::dynallocated);
406     }
407    
408 cbauer 1.6 #ifdef DO_GINAC_ASSERT
409 cbauer 1.1 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
410 cbauer 1.6 GINAC_ASSERT(!is_ex_exactly_of_type((*cit).rest,add));
411 cbauer 1.1 if (is_ex_exactly_of_type((*cit).rest,numeric)) {
412     dbgprint();
413     }
414 cbauer 1.6 GINAC_ASSERT(!is_ex_exactly_of_type((*cit).rest,numeric));
415 cbauer 1.1 }
416 cbauer 1.6 #endif // def DO_GINAC_ASSERT
417 cbauer 1.1
418     if (flags & status_flags::evaluated) {
419 cbauer 1.6 GINAC_ASSERT(seq.size()>0);
420 kreckel 1.10 GINAC_ASSERT((seq.size()>1)||!overall_coeff.is_equal(_ex0()));
421 cbauer 1.1 return *this;
422     }
423    
424     int seq_size=seq.size();
425     if (seq_size==0) {
426     // +(;c) -> c
427     return overall_coeff;
428 kreckel 1.10 } else if ((seq_size==1)&&overall_coeff.is_equal(_ex0())) {
429 cbauer 1.1 // +(x;0) -> x
430     return recombine_pair_to_ex(*(seq.begin()));
431     }
432     return this->hold();
433     }
434    
435     exvector add::get_indices(void) const
436     {
437 cbauer 1.5 // FIXME: all terms in the sum should have the same indices (compatible
438     // tensors) however this is not checked, since there is no function yet
439     // which compares indices (idxvector can be unsorted)
440 cbauer 1.1 if (seq.size()==0) {
441     return exvector();
442     }
443     return (seq.begin())->rest.get_indices();
444     }
445    
446 cbauer 1.14 ex add::simplify_ncmul(const exvector & v) const
447 cbauer 1.1 {
448     if (seq.size()==0) {
449 cbauer 1.13 return inherited::simplify_ncmul(v);
450 cbauer 1.1 }
451     return (*seq.begin()).rest.simplify_ncmul(v);
452     }
453    
454     // protected
455    
456 cbauer 1.14 int add::compare_same_type(const basic & other) const
457 cbauer 1.1 {
458 cbauer 1.13 return inherited::compare_same_type(other);
459 cbauer 1.1 }
460    
461 cbauer 1.14 bool add::is_equal_same_type(const basic & other) const
462 cbauer 1.1 {
463 cbauer 1.13 return inherited::is_equal_same_type(other);
464 cbauer 1.1 }
465    
466     unsigned add::return_type(void) const
467     {
468     if (seq.size()==0) {
469     return return_types::commutative;
470     }
471     return (*seq.begin()).rest.return_type();
472     }
473    
474     unsigned add::return_type_tinfo(void) const
475     {
476     if (seq.size()==0) {
477     return tinfo_key;
478     }
479     return (*seq.begin()).rest.return_type_tinfo();
480     }
481    
482 cbauer 1.14 ex add::thisexpairseq(const epvector & v, const ex & oc) const
483 cbauer 1.1 {
484     return (new add(v,oc))->setflag(status_flags::dynallocated);
485     }
486    
487 cbauer 1.14 ex add::thisexpairseq(epvector * vp, const ex & oc) const
488 cbauer 1.1 {
489     return (new add(vp,oc))->setflag(status_flags::dynallocated);
490     }
491    
492 cbauer 1.14 expair add::split_ex_to_pair(const ex & e) const
493 cbauer 1.1 {
494     if (is_ex_exactly_of_type(e,mul)) {
495 cbauer 1.14 const mul & mulref=ex_to_mul(e);
496 cbauer 1.1 ex numfactor=mulref.overall_coeff;
497     // mul * mulcopyp=static_cast<mul *>(mulref.duplicate());
498     mul * mulcopyp=new mul(mulref);
499 kreckel 1.10 mulcopyp->overall_coeff=_ex1();
500 cbauer 1.1 mulcopyp->clearflag(status_flags::evaluated);
501     mulcopyp->clearflag(status_flags::hash_calculated);
502     return expair(mulcopyp->setflag(status_flags::dynallocated),numfactor);
503     }
504 kreckel 1.10 return expair(e,_ex1());
505 cbauer 1.1 }
506    
507 cbauer 1.14 expair add::combine_ex_with_coeff_to_pair(const ex & e,
508     const ex & c) const
509 cbauer 1.1 {
510 cbauer 1.6 GINAC_ASSERT(is_ex_exactly_of_type(c,numeric));
511 cbauer 1.1 if (is_ex_exactly_of_type(e,mul)) {
512 cbauer 1.14 const mul & mulref=ex_to_mul(e);
513 cbauer 1.1 ex numfactor=mulref.overall_coeff;
514     //mul * mulcopyp=static_cast<mul *>(mulref.duplicate());
515     mul * mulcopyp=new mul(mulref);
516 kreckel 1.10 mulcopyp->overall_coeff=_ex1();
517 cbauer 1.1 mulcopyp->clearflag(status_flags::evaluated);
518     mulcopyp->clearflag(status_flags::hash_calculated);
519 kreckel 1.10 if (are_ex_trivially_equal(c,_ex1())) {
520 cbauer 1.1 return expair(mulcopyp->setflag(status_flags::dynallocated),numfactor);
521 kreckel 1.10 } else if (are_ex_trivially_equal(numfactor,_ex1())) {
522 cbauer 1.1 return expair(mulcopyp->setflag(status_flags::dynallocated),c);
523     }
524     return expair(mulcopyp->setflag(status_flags::dynallocated),
525     ex_to_numeric(numfactor).mul_dyn(ex_to_numeric(c)));
526     } else if (is_ex_exactly_of_type(e,numeric)) {
527 kreckel 1.10 if (are_ex_trivially_equal(c,_ex1())) {
528     return expair(e,_ex1());
529 cbauer 1.1 }
530 kreckel 1.10 return expair(ex_to_numeric(e).mul_dyn(ex_to_numeric(c)),_ex1());
531 cbauer 1.1 }
532     return expair(e,c);
533     }
534    
535 cbauer 1.14 expair add::combine_pair_with_coeff_to_pair(const expair & p,
536     const ex & c) const
537 cbauer 1.1 {
538 cbauer 1.6 GINAC_ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
539     GINAC_ASSERT(is_ex_exactly_of_type(c,numeric));
540 cbauer 1.1
541     if (is_ex_exactly_of_type(p.rest,numeric)) {
542 kreckel 1.10 GINAC_ASSERT(ex_to_numeric(p.coeff).is_equal(_num1())); // should be normalized
543     return expair(ex_to_numeric(p.rest).mul_dyn(ex_to_numeric(c)),_ex1());
544 cbauer 1.1 }
545    
546     return expair(p.rest,ex_to_numeric(p.coeff).mul_dyn(ex_to_numeric(c)));
547     }
548    
549 cbauer 1.14 ex add::recombine_pair_to_ex(const expair & p) const
550 cbauer 1.1 {
551 kreckel 1.10 //if (p.coeff.compare(_ex1())==0) {
552     //if (are_ex_trivially_equal(p.coeff,_ex1())) {
553     if (ex_to_numeric(p.coeff).is_equal(_num1())) {
554 cbauer 1.1 return p.rest;
555     } else {
556     return p.rest*p.coeff;
557     }
558     }
559    
560     ex add::expand(unsigned options) const
561     {
562     epvector * vp=expandchildren(options);
563     if (vp==0) {
564     return *this;
565     }
566     return (new add(vp,overall_coeff))->setflag(status_flags::expanded |
567     status_flags::dynallocated );
568     }
569    
570     //////////
571     // new virtual functions which can be overridden by derived classes
572     //////////
573    
574     // none
575    
576     //////////
577     // non-virtual functions in this class
578     //////////
579    
580     // none
581    
582     //////////
583     // static member variables
584     //////////
585    
586     // protected
587    
588     unsigned add::precedence=40;
589    
590     //////////
591     // global constants
592     //////////
593    
594     const add some_add;
595 cbauer 1.14 const type_info & typeid_add=typeid(some_add);
596 cbauer 1.1
597 frink 1.7 #ifndef NO_GINAC_NAMESPACE
598 cbauer 1.5 } // namespace GiNaC
599 frink 1.7 #endif // ndef NO_GINAC_NAMESPACE

Christian Bauer">Christian Bauer
ViewVC Help
Powered by ViewVC 1.1.15