]> www.ginac.de Git - ginac.git/blob - ginac/ex.h
added to_polynomial(), to complement to_rational()
[ginac.git] / ginac / ex.h
1 /** @file ex.h
2  *
3  *  Interface to GiNaC's light-weight expression handles. */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #ifndef __GINAC_EX_H__
24 #define __GINAC_EX_H__
25
26 #include <iosfwd>
27 #include <functional>
28
29 #include "basic.h"
30
31 namespace GiNaC {
32
33 /** Helper class to initialize the library.  There must be one static object
34  *  of this class in every object file that makes use of our flyweights in
35  *  order to guarantee proper initialization.  Hence we put it into this
36  *  file which is included by every relevant file anyways.  This is modeled
37  *  after section 27.4.2.1.6 of the C++ standard, where cout and friends are
38  *  set up.
39  *
40  *  @see utils.cpp */
41 class library_init {
42 public:
43         library_init();
44         ~library_init();
45 private:
46         static int count;
47 };
48 /** For construction of flyweights, etc. */
49 static library_init library_initializer;
50
51 // Current versions of Cint don't link data declared extern within functions.
52 // FIXME: Fix Cint and later remove this from here.
53 #if defined(G__CINTVERSION)
54 extern const class numeric *_num0_p;
55 #endif
56
57
58 class symbol;
59 class lst;
60 class scalar_products;
61
62
63 /** Lightweight wrapper for GiNaC's symbolic objects.  Basically all it does is
64  *  to hold a pointer to the other objects, manage the reference counting and
65  *  provide methods for manipulation of these objects.  (Some people call such
66  *  a thing a proxy class.) */
67 class ex
68 {
69         friend class archive_node;
70         friend bool are_ex_trivially_equal(const ex &, const ex &);
71         template<class T> friend const T &ex_to(const ex &);
72         template<class T> friend bool is_a(const ex &);
73         template<class T> friend bool is_exactly_a(const ex &);
74         
75 // member functions
76         
77         // default ctor, dtor, copy ctor, assignment operator and helpers
78 public:
79         ex();
80         ~ex();
81         ex(const ex & other);
82         ex & operator=(const ex & other);
83         // other ctors
84 public:
85         ex(const basic & other);
86         ex(int i);
87         ex(unsigned int i);
88         ex(long i);
89         ex(unsigned long i);
90         ex(double const d);
91
92         /** Construct ex from string and a list of symbols. The input grammar is
93          *  similar to the GiNaC output format. All symbols and indices to be used
94          *  in the expression must be specified in a lst in the second argument.
95          *  Undefined symbols and other parser errors will throw an exception. */
96         ex(const std::string &s, const ex &l);
97         
98         // non-virtual functions in this class
99 public:
100         /** Efficiently swap the contents of two expressions. */
101         void swap(ex & other)
102         {
103                 GINAC_ASSERT(bp!=0);
104                 GINAC_ASSERT(bp->flags & status_flags::dynallocated);
105                 GINAC_ASSERT(other.bp!=0);
106                 GINAC_ASSERT(other.bp->flags & status_flags::dynallocated);
107         
108                 basic * tmpbp = bp;
109                 bp = other.bp;
110                 other.bp = tmpbp;
111         }
112
113         void print(const print_context & c, unsigned level = 0) const;
114         void printtree(std::ostream & os) const;
115         void dbgprint(void) const;
116         void dbgprinttree(void) const;
117         bool info(unsigned inf) const { return bp->info(inf); }
118         unsigned nops() const { return bp->nops(); }
119         ex expand(unsigned options=0) const;
120         bool has(const ex & pattern) const { return bp->has(pattern); }
121         ex map(map_function & f) const { return bp->map(f); }
122         ex map(ex (*f)(const ex & e)) const;
123         bool find(const ex & pattern, lst & found) const;
124         int degree(const ex & s) const { return bp->degree(s); }
125         int ldegree(const ex & s) const { return bp->ldegree(s); }
126         ex coeff(const ex & s, int n = 1) const { return bp->coeff(s, n); }
127         ex lcoeff(const ex & s) const { return coeff(s, degree(s)); }
128         ex tcoeff(const ex & s) const { return coeff(s, ldegree(s)); }
129         ex numer(void) const;
130         ex denom(void) const;
131         ex numer_denom(void) const;
132         ex unit(const symbol &x) const;
133         ex content(const symbol &x) const;
134         numeric integer_content(void) const;
135         ex primpart(const symbol &x) const;
136         ex primpart(const symbol &x, const ex &cont) const;
137         ex normal(int level = 0) const;
138         ex to_rational(lst &repl_lst) const;
139         ex to_polynomial(lst &repl_lst) const;
140         ex smod(const numeric &xi) const { return bp->smod(xi); }
141         numeric max_coefficient(void) const;
142         ex collect(const ex & s, bool distributed = false) const { return bp->collect(s, distributed); }
143         ex eval(int level = 0) const { return bp->eval(level); }
144         ex evalf(int level = 0) const { return bp->evalf(level); }
145         ex evalm(void) const { return bp->evalm(); }
146         ex diff(const symbol & s, unsigned nth = 1) const;
147         ex series(const ex & r, int order, unsigned options = 0) const;
148         bool match(const ex & pattern) const;
149         bool match(const ex & pattern, lst & repl_lst) const { return bp->match(pattern, repl_lst); }
150         ex subs(const lst & ls, const lst & lr, unsigned options = 0) const { return bp->subs(ls, lr, options); }
151         ex subs(const ex & e, unsigned options = 0) const { return bp->subs(e, options); }
152         exvector get_free_indices(void) const { return bp->get_free_indices(); }
153         ex simplify_indexed(void) const;
154         ex simplify_indexed(const scalar_products & sp) const;
155         ex symmetrize(void) const;
156         ex symmetrize(const lst & l) const;
157         ex antisymmetrize(void) const;
158         ex antisymmetrize(const lst & l) const;
159         ex symmetrize_cyclic(void) const;
160         ex symmetrize_cyclic(const lst & l) const;
161         ex eval_ncmul(const exvector & v) const { return bp->eval_ncmul(v); }
162         ex operator[](const ex & index) const;
163         ex operator[](int i) const;
164         ex op(int i) const { return bp->op(i); }
165         ex & let_op(int i);
166         ex lhs(void) const;
167         ex rhs(void) const;
168         int compare(const ex & other) const;
169         bool is_equal(const ex & other) const;
170         bool is_zero(void) const { extern const ex _ex0; return is_equal(_ex0); }
171         
172         unsigned return_type(void) const { return bp->return_type(); }
173         unsigned return_type_tinfo(void) const { return bp->return_type_tinfo(); }
174         unsigned gethash(void) const { return bp->gethash(); }
175 private:
176         void construct_from_basic(const basic & other);
177         void construct_from_int(int i);
178         void construct_from_uint(unsigned int i);
179         void construct_from_long(long i);
180         void construct_from_ulong(unsigned long i);
181         void construct_from_double(double d);
182         void construct_from_string_and_lst(const std::string &s, const ex &l);
183         void makewriteable();
184
185 #ifdef OBSCURE_CINT_HACK
186 public:
187         static bool last_created_or_assigned_bp_can_be_converted_to_ex(void)
188         {
189                 if (last_created_or_assigned_bp==0) return false;
190                 if ((last_created_or_assigned_bp->flags &
191                          status_flags::dynallocated)==0) return false;
192                 if ((last_created_or_assigned_bp->flags &
193                          status_flags::evaluated)==0) return false;
194                 return true;
195         }
196 protected:
197         void update_last_created_or_assigned_bp(void)
198         {
199                 if (last_created_or_assigned_bp!=0) {
200                         if (--last_created_or_assigned_bp->refcount == 0) {
201                                 delete last_created_or_assigned_bp;
202                         }
203                 }
204                 last_created_or_assigned_bp = bp;
205                 ++last_created_or_assigned_bp->refcount;
206                 last_created_or_assigned_exp = (long)(void *)(this);
207         }
208 #endif // def OBSCURE_CINT_HACK
209
210 // member variables
211
212 private:
213         basic *bp;      ///< pointer to basic object managed by this
214 #ifdef OBSCURE_CINT_HACK
215 public:
216         static basic * last_created_or_assigned_bp;
217         static basic * dummy_bp;
218         static long last_created_or_assigned_exp;
219 #endif // def OBSCURE_CINT_HACK
220 };
221
222
223 // performance-critical inlined method implementations
224
225 inline
226 ex::ex()
227 {
228         extern const class numeric *_num0_p;
229         bp = (basic*)_num0_p;
230         GINAC_ASSERT(bp!=0);
231         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
232         ++bp->refcount;
233 #ifdef OBSCURE_CINT_HACK
234         update_last_created_or_assigned_bp();
235 #endif // def OBSCURE_CINT_HACK
236 }
237
238 inline
239 ex::~ex()
240 {
241         GINAC_ASSERT(bp!=0);
242         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
243         if (--bp->refcount == 0)
244                 delete bp;
245 }
246
247 inline
248 ex::ex(const ex & other) : bp(other.bp)
249 {
250         GINAC_ASSERT(bp!=0);
251         GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
252         ++bp->refcount;
253 #ifdef OBSCURE_CINT_HACK
254         update_last_created_or_assigned_bp();
255 #endif // def OBSCURE_CINT_HACK
256 }
257
258 inline
259 ex & ex::operator=(const ex & other)
260 {
261         GINAC_ASSERT(bp!=0);
262         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
263         GINAC_ASSERT(other.bp!=0);
264         GINAC_ASSERT(other.bp->flags & status_flags::dynallocated);
265         // NB: must first increment other.bp->refcount, since other might be *this.
266         ++other.bp->refcount;
267         if (--bp->refcount==0)
268                 delete bp;
269         bp = other.bp;
270 #ifdef OBSCURE_CINT_HACK
271         update_last_created_or_assigned_bp();
272 #endif // def OBSCURE_CINT_HACK
273         return *this;
274 }
275
276 inline
277 ex::ex(const basic & other)
278 {
279         construct_from_basic(other);
280 #ifdef OBSCURE_CINT_HACK
281         update_last_created_or_assigned_bp();
282 #endif // def OBSCURE_CINT_HACK
283 }
284
285 inline
286 ex::ex(int i)
287 {
288         construct_from_int(i);
289 #ifdef OBSCURE_CINT_HACK
290         update_last_created_or_assigned_bp();
291 #endif // def OBSCURE_CINT_HACK
292 }
293
294 inline
295 ex::ex(unsigned int i)
296 {
297         construct_from_uint(i);
298 #ifdef OBSCURE_CINT_HACK
299         update_last_created_or_assigned_bp();
300 #endif // def OBSCURE_CINT_HACK
301 }
302
303 inline
304 ex::ex(long i)
305 {
306         construct_from_long(i);
307 #ifdef OBSCURE_CINT_HACK
308         update_last_created_or_assigned_bp();
309 #endif // def OBSCURE_CINT_HACK
310 }
311
312 inline
313 ex::ex(unsigned long i)
314 {
315         construct_from_ulong(i);
316 #ifdef OBSCURE_CINT_HACK
317         update_last_created_or_assigned_bp();
318 #endif // def OBSCURE_CINT_HACK
319 }
320
321 inline
322 ex::ex(double const d)
323 {
324         construct_from_double(d);
325 #ifdef OBSCURE_CINT_HACK
326         update_last_created_or_assigned_bp();
327 #endif // def OBSCURE_CINT_HACK
328 }
329
330 inline
331 ex::ex(const std::string &s, const ex &l)
332 {
333         construct_from_string_and_lst(s, l);
334 #ifdef OBSCURE_CINT_HACK
335         update_last_created_or_assigned_bp();
336 #endif // def OBSCURE_CINT_HACK
337 }
338
339 inline
340 int ex::compare(const ex & other) const
341 {
342         GINAC_ASSERT(bp!=0);
343         GINAC_ASSERT(other.bp!=0);
344         if (bp==other.bp)  // trivial case: both expressions point to same basic
345                 return 0;
346         return bp->compare(*other.bp);
347 }
348
349 inline
350 bool ex::is_equal(const ex & other) const
351 {
352         GINAC_ASSERT(bp!=0);
353         GINAC_ASSERT(other.bp!=0);
354         if (bp==other.bp)  // trivial case: both expressions point to same basic
355                 return true;
356         return bp->is_equal(*other.bp);
357 }
358
359
360 // utility functions
361
362 /** Compare two objects of class quickly without doing a deep tree traversal.
363  *  @return "true" if they are equal
364  *          "false" if equality cannot be established quickly (e1 and e2 may
365  *          still be equal, in this case. */
366 inline bool are_ex_trivially_equal(const ex &e1, const ex &e2)
367 {
368         return e1.bp == e2.bp;
369 }
370
371 // wrapper functions around member functions
372 inline unsigned nops(const ex & thisex)
373 { return thisex.nops(); }
374
375 inline ex expand(const ex & thisex, unsigned options = 0)
376 { return thisex.expand(options); }
377
378 inline bool has(const ex & thisex, const ex & pattern)
379 { return thisex.has(pattern); }
380
381 inline bool find(const ex & thisex, const ex & pattern, lst & found)
382 { return thisex.find(pattern, found); }
383
384 inline int degree(const ex & thisex, const ex & s)
385 { return thisex.degree(s); }
386
387 inline int ldegree(const ex & thisex, const ex & s)
388 { return thisex.ldegree(s); }
389
390 inline ex coeff(const ex & thisex, const ex & s, int n=1)
391 { return thisex.coeff(s, n); }
392
393 inline ex numer(const ex & thisex)
394 { return thisex.numer(); }
395
396 inline ex denom(const ex & thisex)
397 { return thisex.denom(); }
398
399 inline ex numer_denom(const ex & thisex)
400 { return thisex.numer_denom(); }
401
402 inline ex normal(const ex & thisex, int level=0)
403 { return thisex.normal(level); }
404
405 inline ex to_rational(const ex & thisex, lst & repl_lst)
406 { return thisex.to_rational(repl_lst); }
407
408 inline ex to_polynomial(const ex & thisex, lst & repl_lst)
409 { return thisex.to_polynomial(repl_lst); }
410
411 inline ex collect(const ex & thisex, const ex & s, bool distributed = false)
412 { return thisex.collect(s, distributed); }
413
414 inline ex eval(const ex & thisex, int level = 0)
415 { return thisex.eval(level); }
416
417 inline ex evalf(const ex & thisex, int level = 0)
418 { return thisex.evalf(level); }
419
420 inline ex evalm(const ex & thisex)
421 { return thisex.evalm(); }
422
423 inline ex diff(const ex & thisex, const symbol & s, unsigned nth = 1)
424 { return thisex.diff(s, nth); }
425
426 inline ex series(const ex & thisex, const ex & r, int order, unsigned options = 0)
427 { return thisex.series(r, order, options); }
428
429 inline bool match(const ex & thisex, const ex & pattern, lst & repl_lst)
430 { return thisex.match(pattern, repl_lst); }
431
432 inline ex subs(const ex & thisex, const ex & e, unsigned options = 0)
433 { return thisex.subs(e, options); }
434
435 inline ex subs(const ex & thisex, const lst & ls, const lst & lr, unsigned options = 0)
436 { return thisex.subs(ls, lr, options); }
437
438 inline ex simplify_indexed(const ex & thisex)
439 { return thisex.simplify_indexed(); }
440
441 inline ex simplify_indexed(const ex & thisex, const scalar_products & sp)
442 { return thisex.simplify_indexed(sp); }
443
444 inline ex symmetrize(const ex & thisex)
445 { return thisex.symmetrize(); }
446
447 inline ex symmetrize(const ex & thisex, const lst & l)
448 { return thisex.symmetrize(l); }
449
450 inline ex antisymmetrize(const ex & thisex)
451 { return thisex.antisymmetrize(); }
452
453 inline ex antisymmetrize(const ex & thisex, const lst & l)
454 { return thisex.antisymmetrize(l); }
455
456 inline ex symmetrize_cyclic(const ex & thisex)
457 { return thisex.symmetrize_cyclic(); }
458
459 inline ex symmetrize_cyclic(const ex & thisex, const lst & l)
460 { return thisex.symmetrize_cyclic(l); }
461
462 inline ex op(const ex & thisex, int i)
463 { return thisex.op(i); }
464
465 inline ex lhs(const ex & thisex)
466 { return thisex.lhs(); }
467
468 inline ex rhs(const ex & thisex)
469 { return thisex.rhs(); }
470
471 inline bool is_zero(const ex & thisex)
472 { return thisex.is_zero(); }
473
474 inline void swap(ex & e1, ex & e2)
475 { e1.swap(e2); }
476
477 // This makes STL algorithms use the more efficient swap operation for ex objects
478 inline void iter_swap(std::vector<ex>::iterator i1, std::vector<ex>::iterator i2)
479 { i1->swap(*i2); }
480
481
482 /* Function objects for STL sort() etc. */
483 struct ex_is_less : public std::binary_function<ex, ex, bool> {
484         bool operator() (const ex &lh, const ex &rh) const { return lh.compare(rh) < 0; }
485 };
486
487 struct ex_is_equal : public std::binary_function<ex, ex, bool> {
488         bool operator() (const ex &lh, const ex &rh) const { return lh.is_equal(rh); }
489 };
490
491 struct ex_swap : public std::binary_function<ex, ex, void> {
492         void operator() (ex &lh, ex &rh) const { lh.swap(rh); }
493 };
494
495
496 /* Convert function pointer to function object suitable for map(). */
497 class pointer_to_map_function : public map_function {
498 protected:
499         ex (*ptr)(const ex &);
500 public:
501         explicit pointer_to_map_function(ex (*x)(const ex &)) : ptr(x) {}
502         ex operator()(const ex & e) { return ptr(e); }
503 };
504
505 template<class T1>
506 class pointer_to_map_function_1arg : public map_function {
507 protected:
508         ex (*ptr)(const ex &, T1);
509         T1 arg1;
510 public:
511         explicit pointer_to_map_function_1arg(ex (*x)(const ex &, T1), T1 a1) : ptr(x), arg1(a1) {}
512         ex operator()(const ex & e) { return ptr(e, arg1); }
513 };
514
515 template<class T1, class T2>
516 class pointer_to_map_function_2args : public map_function {
517 protected:
518         ex (*ptr)(const ex &, T1, T2);
519         T1 arg1;
520         T2 arg2;
521 public:
522         explicit pointer_to_map_function_2args(ex (*x)(const ex &, T1, T2), T1 a1, T2 a2) : ptr(x), arg1(a1), arg2(a2) {}
523         ex operator()(const ex & e) { return ptr(e, arg1, arg2); }
524 };
525
526 template<class T1, class T2, class T3>
527 class pointer_to_map_function_3args : public map_function {
528 protected:
529         ex (*ptr)(const ex &, T1, T2, T3);
530         T1 arg1;
531         T2 arg2;
532         T3 arg3;
533 public:
534         explicit pointer_to_map_function_3args(ex (*x)(const ex &, T1, T2, T3), T1 a1, T2 a2, T3 a3) : ptr(x), arg1(a1), arg2(a2), arg3(a3) {}
535         ex operator()(const ex & e) { return ptr(e, arg1, arg2, arg3); }
536 };
537
538 inline ex ex::map(ex (*f)(const ex & e)) const
539 {
540         pointer_to_map_function fcn(f);
541         return bp->map(fcn);
542 }
543
544
545 } // namespace GiNaC
546
547 #endif // ndef __GINAC_EX_H__