]> www.ginac.de Git - ginac.git/blob - ginac/ex.h
Happy New Year!
[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-2004 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 inline bool are_ex_trivially_equal(const ex &, const ex &);
71         template<class T> friend inline const T &ex_to(const ex &);
72         template<class T> friend inline bool is_a(const ex &);
73         template<class T> friend inline bool is_exactly_a(const ex &);
74         
75         // default ctor, dtor, copy ctor, assignment operator and helpers
76 public:
77         ex();
78         ~ex();
79         ex(const ex & other);
80         ex & operator=(const ex & other);
81         // other ctors
82 public:
83         ex(const basic & other);
84         ex(int i);
85         ex(unsigned int i);
86         ex(long i);
87         ex(unsigned long i);
88         ex(double const d);
89
90         /** Construct ex from string and a list of symbols. The input grammar is
91          *  similar to the GiNaC output format. All symbols and indices to be used
92          *  in the expression must be specified in a lst in the second argument.
93          *  Undefined symbols and other parser errors will throw an exception. */
94         ex(const std::string &s, const ex &l);
95         
96         // non-virtual functions in this class
97 public:
98         /** Efficiently swap the contents of two expressions. */
99         void swap(ex & other)
100         {
101                 GINAC_ASSERT(bp!=0);
102                 GINAC_ASSERT(bp->flags & status_flags::dynallocated);
103                 GINAC_ASSERT(other.bp!=0);
104                 GINAC_ASSERT(other.bp->flags & status_flags::dynallocated);
105         
106                 basic * tmpbp = bp;
107                 bp = other.bp;
108                 other.bp = tmpbp;
109         }
110
111         void print(const print_context & c, unsigned level = 0) const;
112         void dbgprint(void) const;
113         void dbgprinttree(void) const;
114         bool info(unsigned inf) const { return bp->info(inf); }
115         size_t nops() const { return bp->nops(); }
116         ex expand(unsigned options=0) const;
117         bool has(const ex & pattern) const { return bp->has(pattern); }
118         ex map(map_function & f) const { return bp->map(f); }
119         ex map(ex (*f)(const ex & e)) const;
120         bool find(const ex & pattern, lst & found) const;
121         int degree(const ex & s) const { return bp->degree(s); }
122         int ldegree(const ex & s) const { return bp->ldegree(s); }
123         ex coeff(const ex & s, int n = 1) const { return bp->coeff(s, n); }
124         ex lcoeff(const ex & s) const { return coeff(s, degree(s)); }
125         ex tcoeff(const ex & s) const { return coeff(s, ldegree(s)); }
126         ex numer(void) const;
127         ex denom(void) const;
128         ex numer_denom(void) const;
129         ex unit(const symbol &x) const;
130         ex content(const symbol &x) const;
131         numeric integer_content(void) const;
132         ex primpart(const symbol &x) const;
133         ex primpart(const symbol &x, const ex &cont) const;
134         ex normal(int level = 0) const;
135         ex to_rational(lst &repl_lst) const;
136         ex to_polynomial(lst &repl_lst) const;
137         ex smod(const numeric &xi) const { return bp->smod(xi); }
138         numeric max_coefficient(void) const;
139         ex collect(const ex & s, bool distributed = false) const { return bp->collect(s, distributed); }
140         ex eval(int level = 0) const { return bp->eval(level); }
141         ex evalf(int level = 0) const { return bp->evalf(level); }
142         ex evalm(void) const { return bp->evalm(); }
143         ex diff(const symbol & s, unsigned nth = 1) const;
144         ex series(const ex & r, int order, unsigned options = 0) const;
145         bool match(const ex & pattern) const;
146         bool match(const ex & pattern, lst & repl_lst) const { return bp->match(pattern, repl_lst); }
147         ex subs(const lst & ls, const lst & lr, unsigned options = 0) const { return bp->subs(ls, lr, options); }
148         ex subs(const ex & e, unsigned options = 0) const { return bp->subs(e, options); }
149         exvector get_free_indices(void) const { return bp->get_free_indices(); }
150         ex simplify_indexed(void) const;
151         ex simplify_indexed(const scalar_products & sp) const;
152         ex symmetrize(void) const;
153         ex symmetrize(const lst & l) const;
154         ex antisymmetrize(void) const;
155         ex antisymmetrize(const lst & l) const;
156         ex symmetrize_cyclic(void) const;
157         ex symmetrize_cyclic(const lst & l) const;
158         ex eval_ncmul(const exvector & v) const { return bp->eval_ncmul(v); }
159         ex op(size_t i) const { return bp->op(i); }
160         ex operator[](const ex & index) const { return (*bp)[index]; }
161         ex operator[](size_t i) const { return (*bp)[i]; }
162         ex & let_op(size_t i);
163         ex & operator[](const ex & index);
164         ex & operator[](size_t i);
165         ex lhs(void) const;
166         ex rhs(void) const;
167         int compare(const ex & other) const;
168         bool is_equal(const ex & other) const;
169         bool is_zero(void) const { extern const ex _ex0; return is_equal(_ex0); }
170         
171         unsigned return_type(void) const { return bp->return_type(); }
172         unsigned return_type_tinfo(void) const { return bp->return_type_tinfo(); }
173         unsigned gethash(void) const { return bp->gethash(); }
174 private:
175         void construct_from_basic(const basic & other);
176         void construct_from_int(int i);
177         void construct_from_uint(unsigned int i);
178         void construct_from_long(long i);
179         void construct_from_ulong(unsigned long i);
180         void construct_from_double(double d);
181         void construct_from_string_and_lst(const std::string &s, const ex &l);
182         void makewriteable();
183
184 #ifdef OBSCURE_CINT_HACK
185 public:
186         static bool last_created_or_assigned_bp_can_be_converted_to_ex(void)
187         {
188                 if (last_created_or_assigned_bp==0) return false;
189                 if ((last_created_or_assigned_bp->flags &
190                          status_flags::dynallocated)==0) return false;
191                 if ((last_created_or_assigned_bp->flags &
192                          status_flags::evaluated)==0) return false;
193                 return true;
194         }
195 protected:
196         void update_last_created_or_assigned_bp(void)
197         {
198                 if (last_created_or_assigned_bp!=0) {
199                         if (--last_created_or_assigned_bp->refcount == 0) {
200                                 delete last_created_or_assigned_bp;
201                         }
202                 }
203                 last_created_or_assigned_bp = bp;
204                 ++last_created_or_assigned_bp->refcount;
205                 last_created_or_assigned_exp = (long)(void *)(this);
206         }
207 #endif // def OBSCURE_CINT_HACK
208
209 // member variables
210
211 private:
212         basic *bp;      ///< pointer to basic object managed by this
213 #ifdef OBSCURE_CINT_HACK
214 public:
215         static basic * last_created_or_assigned_bp;
216         static basic * dummy_bp;
217         static long last_created_or_assigned_exp;
218 #endif // def OBSCURE_CINT_HACK
219 };
220
221
222 // performance-critical inlined method implementations
223
224 inline
225 ex::ex()
226 {
227         extern const class numeric *_num0_p;
228         bp = (basic*)_num0_p;
229         GINAC_ASSERT(bp!=0);
230         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
231         ++bp->refcount;
232 #ifdef OBSCURE_CINT_HACK
233         update_last_created_or_assigned_bp();
234 #endif // def OBSCURE_CINT_HACK
235 }
236
237 inline
238 ex::~ex()
239 {
240         GINAC_ASSERT(bp!=0);
241         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
242         if (--bp->refcount == 0)
243                 delete bp;
244 }
245
246 inline
247 ex::ex(const ex & other) : bp(other.bp)
248 {
249         GINAC_ASSERT(bp!=0);
250         GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
251         ++bp->refcount;
252 #ifdef OBSCURE_CINT_HACK
253         update_last_created_or_assigned_bp();
254 #endif // def OBSCURE_CINT_HACK
255 }
256
257 inline
258 ex & ex::operator=(const ex & other)
259 {
260         GINAC_ASSERT(bp!=0);
261         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
262         GINAC_ASSERT(other.bp!=0);
263         GINAC_ASSERT(other.bp->flags & status_flags::dynallocated);
264         // NB: must first increment other.bp->refcount, since other might be *this.
265         ++other.bp->refcount;
266         if (--bp->refcount==0)
267                 delete bp;
268         bp = other.bp;
269 #ifdef OBSCURE_CINT_HACK
270         update_last_created_or_assigned_bp();
271 #endif // def OBSCURE_CINT_HACK
272         return *this;
273 }
274
275 inline
276 ex::ex(const basic & other)
277 {
278         construct_from_basic(other);
279 #ifdef OBSCURE_CINT_HACK
280         update_last_created_or_assigned_bp();
281 #endif // def OBSCURE_CINT_HACK
282 }
283
284 inline
285 ex::ex(int i)
286 {
287         construct_from_int(i);
288 #ifdef OBSCURE_CINT_HACK
289         update_last_created_or_assigned_bp();
290 #endif // def OBSCURE_CINT_HACK
291 }
292
293 inline
294 ex::ex(unsigned int i)
295 {
296         construct_from_uint(i);
297 #ifdef OBSCURE_CINT_HACK
298         update_last_created_or_assigned_bp();
299 #endif // def OBSCURE_CINT_HACK
300 }
301
302 inline
303 ex::ex(long i)
304 {
305         construct_from_long(i);
306 #ifdef OBSCURE_CINT_HACK
307         update_last_created_or_assigned_bp();
308 #endif // def OBSCURE_CINT_HACK
309 }
310
311 inline
312 ex::ex(unsigned long i)
313 {
314         construct_from_ulong(i);
315 #ifdef OBSCURE_CINT_HACK
316         update_last_created_or_assigned_bp();
317 #endif // def OBSCURE_CINT_HACK
318 }
319
320 inline
321 ex::ex(double const d)
322 {
323         construct_from_double(d);
324 #ifdef OBSCURE_CINT_HACK
325         update_last_created_or_assigned_bp();
326 #endif // def OBSCURE_CINT_HACK
327 }
328
329 inline
330 ex::ex(const std::string &s, const ex &l)
331 {
332         construct_from_string_and_lst(s, l);
333 #ifdef OBSCURE_CINT_HACK
334         update_last_created_or_assigned_bp();
335 #endif // def OBSCURE_CINT_HACK
336 }
337
338 inline
339 int ex::compare(const ex & other) const
340 {
341         GINAC_ASSERT(bp!=0);
342         GINAC_ASSERT(other.bp!=0);
343         if (bp==other.bp)  // trivial case: both expressions point to same basic
344                 return 0;
345         return bp->compare(*other.bp);
346 }
347
348 inline
349 bool ex::is_equal(const ex & other) const
350 {
351         GINAC_ASSERT(bp!=0);
352         GINAC_ASSERT(other.bp!=0);
353         if (bp==other.bp)  // trivial case: both expressions point to same basic
354                 return true;
355         return bp->is_equal(*other.bp);
356 }
357
358
359 // utility functions
360
361 /** Compare two objects of class quickly without doing a deep tree traversal.
362  *  @return "true" if they are equal
363  *          "false" if equality cannot be established quickly (e1 and e2 may
364  *          still be equal, in this case. */
365 inline bool are_ex_trivially_equal(const ex &e1, const ex &e2)
366 {
367         return e1.bp == e2.bp;
368 }
369
370 // wrapper functions around member functions
371 inline size_t nops(const ex & thisex)
372 { return thisex.nops(); }
373
374 inline ex expand(const ex & thisex, unsigned options = 0)
375 { return thisex.expand(options); }
376
377 inline bool has(const ex & thisex, const ex & pattern)
378 { return thisex.has(pattern); }
379
380 inline bool find(const ex & thisex, const ex & pattern, lst & found)
381 { return thisex.find(pattern, found); }
382
383 inline int degree(const ex & thisex, const ex & s)
384 { return thisex.degree(s); }
385
386 inline int ldegree(const ex & thisex, const ex & s)
387 { return thisex.ldegree(s); }
388
389 inline ex coeff(const ex & thisex, const ex & s, int n=1)
390 { return thisex.coeff(s, n); }
391
392 inline ex numer(const ex & thisex)
393 { return thisex.numer(); }
394
395 inline ex denom(const ex & thisex)
396 { return thisex.denom(); }
397
398 inline ex numer_denom(const ex & thisex)
399 { return thisex.numer_denom(); }
400
401 inline ex normal(const ex & thisex, int level=0)
402 { return thisex.normal(level); }
403
404 inline ex to_rational(const ex & thisex, lst & repl_lst)
405 { return thisex.to_rational(repl_lst); }
406
407 inline ex to_polynomial(const ex & thisex, lst & repl_lst)
408 { return thisex.to_polynomial(repl_lst); }
409
410 inline ex collect(const ex & thisex, const ex & s, bool distributed = false)
411 { return thisex.collect(s, distributed); }
412
413 inline ex eval(const ex & thisex, int level = 0)
414 { return thisex.eval(level); }
415
416 inline ex evalf(const ex & thisex, int level = 0)
417 { return thisex.evalf(level); }
418
419 inline ex evalm(const ex & thisex)
420 { return thisex.evalm(); }
421
422 inline ex diff(const ex & thisex, const symbol & s, unsigned nth = 1)
423 { return thisex.diff(s, nth); }
424
425 inline ex series(const ex & thisex, const ex & r, int order, unsigned options = 0)
426 { return thisex.series(r, order, options); }
427
428 inline bool match(const ex & thisex, const ex & pattern, lst & repl_lst)
429 { return thisex.match(pattern, repl_lst); }
430
431 inline ex subs(const ex & thisex, const ex & e, unsigned options = 0)
432 { return thisex.subs(e, options); }
433
434 inline ex subs(const ex & thisex, const lst & ls, const lst & lr, unsigned options = 0)
435 { return thisex.subs(ls, lr, options); }
436
437 inline ex simplify_indexed(const ex & thisex)
438 { return thisex.simplify_indexed(); }
439
440 inline ex simplify_indexed(const ex & thisex, const scalar_products & sp)
441 { return thisex.simplify_indexed(sp); }
442
443 inline ex symmetrize(const ex & thisex)
444 { return thisex.symmetrize(); }
445
446 inline ex symmetrize(const ex & thisex, const lst & l)
447 { return thisex.symmetrize(l); }
448
449 inline ex antisymmetrize(const ex & thisex)
450 { return thisex.antisymmetrize(); }
451
452 inline ex antisymmetrize(const ex & thisex, const lst & l)
453 { return thisex.antisymmetrize(l); }
454
455 inline ex symmetrize_cyclic(const ex & thisex)
456 { return thisex.symmetrize_cyclic(); }
457
458 inline ex symmetrize_cyclic(const ex & thisex, const lst & l)
459 { return thisex.symmetrize_cyclic(l); }
460
461 inline ex op(const ex & thisex, size_t i)
462 { return thisex.op(i); }
463
464 inline ex lhs(const ex & thisex)
465 { return thisex.lhs(); }
466
467 inline ex rhs(const ex & thisex)
468 { return thisex.rhs(); }
469
470 inline bool is_zero(const ex & thisex)
471 { return thisex.is_zero(); }
472
473 inline void swap(ex & e1, ex & e2)
474 { e1.swap(e2); }
475
476 /* Function objects for STL sort() etc. */
477 struct ex_is_less : public std::binary_function<ex, ex, bool> {
478         bool operator() (const ex &lh, const ex &rh) const { return lh.compare(rh) < 0; }
479 };
480
481 struct ex_is_equal : public std::binary_function<ex, ex, bool> {
482         bool operator() (const ex &lh, const ex &rh) const { return lh.is_equal(rh); }
483 };
484
485 struct op0_is_equal : public std::binary_function<ex, ex, bool> {
486         bool operator() (const ex &lh, const ex &rh) const { return lh.op(0).is_equal(rh.op(0)); }
487 };
488
489 struct ex_swap : public std::binary_function<ex, ex, void> {
490         void operator() (ex &lh, ex &rh) const { lh.swap(rh); }
491 };
492
493
494 /* Convert function pointer to function object suitable for map(). */
495 class pointer_to_map_function : public map_function {
496 protected:
497         ex (*ptr)(const ex &);
498 public:
499         explicit pointer_to_map_function(ex (*x)(const ex &)) : ptr(x) {}
500         ex operator()(const ex & e) { return ptr(e); }
501 };
502
503 template<class T1>
504 class pointer_to_map_function_1arg : public map_function {
505 protected:
506         ex (*ptr)(const ex &, T1);
507         T1 arg1;
508 public:
509         explicit pointer_to_map_function_1arg(ex (*x)(const ex &, T1), T1 a1) : ptr(x), arg1(a1) {}
510         ex operator()(const ex & e) { return ptr(e, arg1); }
511 };
512
513 template<class T1, class T2>
514 class pointer_to_map_function_2args : public map_function {
515 protected:
516         ex (*ptr)(const ex &, T1, T2);
517         T1 arg1;
518         T2 arg2;
519 public:
520         explicit pointer_to_map_function_2args(ex (*x)(const ex &, T1, T2), T1 a1, T2 a2) : ptr(x), arg1(a1), arg2(a2) {}
521         ex operator()(const ex & e) { return ptr(e, arg1, arg2); }
522 };
523
524 template<class T1, class T2, class T3>
525 class pointer_to_map_function_3args : public map_function {
526 protected:
527         ex (*ptr)(const ex &, T1, T2, T3);
528         T1 arg1;
529         T2 arg2;
530         T3 arg3;
531 public:
532         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) {}
533         ex operator()(const ex & e) { return ptr(e, arg1, arg2, arg3); }
534 };
535
536 inline ex ex::map(ex (*f)(const ex & e)) const
537 {
538         pointer_to_map_function fcn(f);
539         return bp->map(fcn);
540 }
541
542 // convenience type checker template functions
543
544 /** Check if ex is a handle to a T, including base classes. */
545 template <class T>
546 inline bool is_a(const ex &obj)
547 {
548         return is_a<T>(*obj.bp);
549 }
550
551 /** Check if ex is a handle to a T, not including base classes. */
552 template <class T>
553 inline bool is_exactly_a(const ex &obj)
554 {
555         return is_exactly_a<T>(*obj.bp);
556 }
557
558 /** Return a reference to the basic-derived class T object embedded in an
559  *  expression.  This is fast but unsafe: the result is undefined if the
560  *  expression does not contain a T object at its top level.  Hence, you
561  *  should generally check the type of e first.
562  *
563  *  @param e expression
564  *  @return reference to object of class T
565  *  @see is_exactly_a<class T>() */
566 template <class T>
567 inline const T &ex_to(const ex &e)
568 {
569         GINAC_ASSERT(is_a<T>(e));
570         return static_cast<const T &>(*e.bp);
571 }
572
573 } // namespace GiNaC
574
575
576 // Specializations of Standard Library algorithms
577 namespace std {
578
579 /** Specialization of std::swap() for ex objects. */
580 template <>
581 inline void swap(GiNaC::ex &a, GiNaC::ex &b)
582 {
583         a.swap(b);
584 }
585
586 /** Specialization of std::iter_swap() for vector<ex> iterators. */
587 template <>
588 inline void iter_swap(vector<GiNaC::ex>::iterator i1, vector<GiNaC::ex>::iterator i2)
589 {
590         i1->swap(*i2);
591 }
592
593 } // namespace std
594
595 #endif // ndef __GINAC_EX_H__