]> www.ginac.de Git - ginac.git/blob - ginac/ex.cpp
eeb7e076fcff0ec33808248d90359612a38e32fd
[ginac.git] / ginac / ex.cpp
1 /** @file ex.cpp
2  *
3  *  Implementation of GiNaC's light-weight expression handles. */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2023 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 "ex.h"
24 #include "add.h"
25 #include "mul.h"
26 #include "ncmul.h"
27 #include "numeric.h"
28 #include "matrix.h"
29 #include "power.h"
30 #include "lst.h"
31 #include "relational.h"
32 #include "utils.h"
33
34 #include <iostream>
35 #include <stdexcept>
36
37 namespace GiNaC {
38
39 //////////
40 // other constructors
41 //////////
42
43 // none (all inlined)
44
45 //////////
46 // non-virtual functions in this class
47 //////////
48
49 // public
50         
51 /** Print expression to stream. The formatting of the output is determined
52  *  by the kind of print_context object that is passed. Possible formattings
53  *  include ginsh-parsable output (the default), tree-like output for
54  *  debugging, and C++ source.
55  *  @see print_context */
56 void ex::print(const print_context & c, unsigned level) const
57 {
58         bp->print(c, level);
59 }
60
61 /** Little wrapper arount print to be called within a debugger. */
62 void ex::dbgprint() const
63 {
64         bp->dbgprint();
65 }
66
67 /** Little wrapper arount printtree to be called within a debugger. */
68 void ex::dbgprinttree() const
69 {
70         bp->dbgprinttree();
71 }
72
73 /** Expand an expression.
74  *  @param options  see GiNaC::expand_options */
75 ex ex::expand(unsigned options) const
76 {
77         if (options == 0 && (bp->flags & status_flags::expanded)) // The "expanded" flag only covers the standard options; someone might want to re-expand with different options
78                 return *this;
79         else
80                 return bp->expand(options);
81 }
82
83 /** Compute partial derivative of an expression.
84  *
85  *  @param s  symbol by which the expression is derived
86  *  @param nth  order of derivative (default 1)
87  *  @return partial derivative as a new expression */
88 ex ex::diff(const symbol & s, unsigned nth) const
89 {
90         if (!nth)
91                 return *this;
92         else
93                 return bp->diff(s, nth);
94 }
95
96 /** Check whether expression matches a specified pattern. */
97 bool ex::match(const ex & pattern) const
98 {
99         exmap repl_lst;
100         return bp->match(pattern, repl_lst);
101 }
102
103 /** Find all occurrences of a pattern. The found matches are appended to
104  *  the "found" list. If the expression itself matches the pattern, the
105  *  children are not further examined. This function returns true when any
106  *  matches were found. */
107 bool ex::find(const ex & pattern, exset& found) const
108 {
109         if (match(pattern)) {
110                 found.insert(*this);
111                 return true;
112         }
113         bool any_found = false;
114         for (size_t i=0; i<nops(); i++)
115                 if (op(i).find(pattern, found))
116                         any_found = true;
117         return any_found;
118 }
119
120 /** Substitute objects in an expression (syntactic substitution) and return
121  *  the result as a new expression. */
122 ex ex::subs(const lst & ls, const lst & lr, unsigned options) const
123 {
124         GINAC_ASSERT(ls.nops() == lr.nops());
125
126         // Convert the lists to a map
127         exmap m;
128         for (auto its = ls.begin(), itr = lr.begin(); its != ls.end(); ++its, ++itr) {
129                 m.insert(std::make_pair(*its, *itr));
130
131                 // Search for products and powers in the expressions to be substituted
132                 // (for an optimization in expairseq::subs())
133                 if (is_exactly_a<mul>(*its) || is_exactly_a<power>(*its))
134                         options |= subs_options::pattern_is_product;
135         }
136         if (!(options & subs_options::pattern_is_product))
137                 options |= subs_options::pattern_is_not_product;
138
139         return bp->subs(m, options);
140 }
141
142 /** Substitute objects in an expression (syntactic substitution) and return
143  *  the result as a new expression.  There are two valid types of
144  *  replacement arguments: 1) a relational like object==ex and 2) a list of
145  *  relationals lst{object1==ex1,object2==ex2,...}. */
146 ex ex::subs(const ex & e, unsigned options) const
147 {
148         if (e.info(info_flags::relation_equal)) {
149
150                 // Argument is a relation: convert it to a map
151                 exmap m;
152                 const ex & s = e.op(0);
153                 m.insert(std::make_pair(s, e.op(1)));
154
155                 if (is_exactly_a<mul>(s) || is_exactly_a<power>(s))
156                         options |= subs_options::pattern_is_product;
157                 else
158                         options |= subs_options::pattern_is_not_product;
159
160                 return bp->subs(m, options);
161
162         } else if (e.info(info_flags::list)) {
163
164                 // Argument is a list: convert it to a map
165                 exmap m;
166                 GINAC_ASSERT(is_a<lst>(e));
167                 for (auto & r : ex_to<lst>(e)) {
168                         if (!r.info(info_flags::relation_equal))
169                                 throw(std::invalid_argument("basic::subs(ex): argument must be a list of equations"));
170                         const ex & s = r.op(0);
171                         m.insert(std::make_pair(s, r.op(1)));
172
173                         // Search for products and powers in the expressions to be substituted
174                         // (for an optimization in expairseq::subs())
175                         if (is_exactly_a<mul>(s) || is_exactly_a<power>(s))
176                                 options |= subs_options::pattern_is_product;
177                 }
178                 if (!(options & subs_options::pattern_is_product))
179                         options |= subs_options::pattern_is_not_product;
180
181                 return bp->subs(m, options);
182
183         } else
184                 throw(std::invalid_argument("ex::subs(ex): argument must be a relation_equal or a list"));
185 }
186
187 /** Traverse expression tree with given visitor, preorder traversal. */
188 void ex::traverse_preorder(visitor & v) const
189 {
190         accept(v);
191
192         size_t n = nops();
193         for (size_t i = 0; i < n; ++i)
194                 op(i).traverse_preorder(v);
195 }
196
197 /** Traverse expression tree with given visitor, postorder traversal. */
198 void ex::traverse_postorder(visitor & v) const
199 {
200         size_t n = nops();
201         for (size_t i = 0; i < n; ++i)
202                 op(i).traverse_postorder(v);
203
204         accept(v);
205 }
206
207 /** Return modifiable operand/member at position i. */
208 ex & ex::let_op(size_t i)
209 {
210         makewriteable();
211         return bp->let_op(i);
212 }
213
214 ex & ex::operator[](const ex & index)
215 {
216         makewriteable();
217         return (*bp)[index];
218 }
219
220 ex & ex::operator[](size_t i)
221 {
222         makewriteable();
223         return (*bp)[i];
224 }
225
226 /** Left hand side of relational expression. */
227 ex ex::lhs() const
228 {
229         if (!is_a<relational>(*this))
230                 throw std::runtime_error("ex::lhs(): not a relation");
231         return bp->op(0);
232 }
233
234 /** Right hand side of relational expression. */
235 ex ex::rhs() const
236 {
237         if (!is_a<relational>(*this))
238                 throw std::runtime_error("ex::rhs(): not a relation");
239         return bp->op(1);
240 }
241
242 /** Check whether expression is a polynomial. */
243 bool ex::is_polynomial(const ex & vars) const
244 {
245         if (is_a<lst>(vars)) {
246                 const lst & varlst = ex_to<lst>(vars);
247                 for (auto & it : varlst)
248                         if (!bp->is_polynomial(it))
249                                 return false;
250                 return true;
251         }
252         else
253                 return bp->is_polynomial(vars);
254 }
255
256 /** Check whether expression is zero or zero matrix. */
257 bool ex::is_zero_matrix() const
258 {
259         if (is_zero())
260                 return  true;
261         else {
262                 ex e = evalm();
263                 return is_a<matrix>(e) && ex_to<matrix>(e).is_zero_matrix();
264         }
265 }
266
267 // private
268
269 /** Make this ex writable (if more than one ex handle the same basic) by 
270  *  unlinking the object and creating an unshared copy of it. */
271 void ex::makewriteable()
272 {
273         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
274         bp.makewritable();
275         GINAC_ASSERT(bp->get_refcount() == 1);
276 }
277
278 /** Share equal objects between expressions.
279  *  @see ex::compare(const ex &) */
280 void ex::share(const ex & other) const
281 {
282         if ((bp->flags | other.bp->flags) & status_flags::not_shareable)
283                 return;
284
285         if (bp->get_refcount() <= other.bp->get_refcount())
286                 bp = other.bp;
287         else
288                 other.bp = bp;
289 }
290
291 /** Helper function for the ex-from-basic constructor. This is where GiNaC's
292  *  automatic evaluator and memory management are implemented.
293  *  @see ex::ex(const basic &) */
294 ptr<basic> ex::construct_from_basic(const basic & other)
295 {
296         if (!(other.flags & status_flags::evaluated)) {
297
298                 // The object is not yet evaluated, so call eval() to evaluate
299                 // the top level. This will return either
300                 //  a) the original object with status_flags::evaluated set (when the
301                 //     eval() implementation calls hold())
302                 // or
303                 //  b) a different expression.
304                 //
305                 // eval() returns an ex, not a basic&, so this will go through
306                 // construct_from_basic() a second time. In case a) we end up in
307                 // the "else" branch below. In case b) we end up here again and
308                 // apply eval() once more. The recursion stops when eval() calls
309                 // hold() or returns an object that already has its "evaluated"
310                 // flag set, such as a symbol or a numeric.
311                 const ex & tmpex = other.eval();
312
313                 // Eventually, the eval() recursion goes through the "else" branch
314                 // below, which assures that the object pointed to by tmpex.bp is
315                 // allocated on the heap (either it was already on the heap or it
316                 // is a heap-allocated duplicate of another object).
317                 GINAC_ASSERT(tmpex.bp->flags & status_flags::dynallocated); 
318
319                 // If the original object is not referenced but heap-allocated,
320                 // it means that eval() hit case b) above. The original object is
321                 // no longer needed (it evaluated into something different), so we
322                 // delete it (because nobody else will).
323                 if ((other.get_refcount() == 0) && (other.flags & status_flags::dynallocated))
324                         delete &other; // yes, you can apply delete to a const pointer
325
326                 // We can't return a basic& here because the tmpex is destroyed as
327                 // soon as we leave the function, which would deallocate the
328                 // evaluated object.
329                 return tmpex.bp;
330
331         } else {
332
333                 // The easy case: making an "ex" out of an evaluated object.
334                 if (other.flags & status_flags::dynallocated) {
335
336                         // The object is already heap-allocated, so we can just make
337                         // another reference to it.
338                         return ptr<basic>(const_cast<basic &>(other));
339
340                 } else {
341
342                         // The object is not heap-allocated, so we create a duplicate
343                         // on the heap.
344                         basic *bp = other.duplicate();
345                         bp->setflag(status_flags::dynallocated);
346                         GINAC_ASSERT(bp->get_refcount() == 0);
347                         return bp;
348                 }
349         }
350 }
351
352 basic & ex::construct_from_int(int i)
353 {
354         switch (i) {  // prefer flyweights over new objects
355         case -12:
356                 return *const_cast<numeric *>(_num_12_p);
357         case -11:
358                 return *const_cast<numeric *>(_num_11_p);
359         case -10:
360                 return *const_cast<numeric *>(_num_10_p);
361         case -9:
362                 return *const_cast<numeric *>(_num_9_p);
363         case -8:
364                 return *const_cast<numeric *>(_num_8_p);
365         case -7:
366                 return *const_cast<numeric *>(_num_7_p);
367         case -6:
368                 return *const_cast<numeric *>(_num_6_p);
369         case -5:
370                 return *const_cast<numeric *>(_num_5_p);
371         case -4:
372                 return *const_cast<numeric *>(_num_4_p);
373         case -3:
374                 return *const_cast<numeric *>(_num_3_p);
375         case -2:
376                 return *const_cast<numeric *>(_num_2_p);
377         case -1:
378                 return *const_cast<numeric *>(_num_1_p);
379         case 0:
380                 return *const_cast<numeric *>(_num0_p);
381         case 1:
382                 return *const_cast<numeric *>(_num1_p);
383         case 2:
384                 return *const_cast<numeric *>(_num2_p);
385         case 3:
386                 return *const_cast<numeric *>(_num3_p);
387         case 4:
388                 return *const_cast<numeric *>(_num4_p);
389         case 5:
390                 return *const_cast<numeric *>(_num5_p);
391         case 6:
392                 return *const_cast<numeric *>(_num6_p);
393         case 7:
394                 return *const_cast<numeric *>(_num7_p);
395         case 8:
396                 return *const_cast<numeric *>(_num8_p);
397         case 9:
398                 return *const_cast<numeric *>(_num9_p);
399         case 10:
400                 return *const_cast<numeric *>(_num10_p);
401         case 11:
402                 return *const_cast<numeric *>(_num11_p);
403         case 12:
404                 return *const_cast<numeric *>(_num12_p);
405         default:
406                 return dynallocate<numeric>(i);
407         }
408 }
409         
410 basic & ex::construct_from_uint(unsigned int i)
411 {
412         switch (i) {  // prefer flyweights over new objects
413         case 0:
414                 return *const_cast<numeric *>(_num0_p);
415         case 1:
416                 return *const_cast<numeric *>(_num1_p);
417         case 2:
418                 return *const_cast<numeric *>(_num2_p);
419         case 3:
420                 return *const_cast<numeric *>(_num3_p);
421         case 4:
422                 return *const_cast<numeric *>(_num4_p);
423         case 5:
424                 return *const_cast<numeric *>(_num5_p);
425         case 6:
426                 return *const_cast<numeric *>(_num6_p);
427         case 7:
428                 return *const_cast<numeric *>(_num7_p);
429         case 8:
430                 return *const_cast<numeric *>(_num8_p);
431         case 9:
432                 return *const_cast<numeric *>(_num9_p);
433         case 10:
434                 return *const_cast<numeric *>(_num10_p);
435         case 11:
436                 return *const_cast<numeric *>(_num11_p);
437         case 12:
438                 return *const_cast<numeric *>(_num12_p);
439         default:
440                 return dynallocate<numeric>(i);
441         }
442 }
443         
444 basic & ex::construct_from_long(long i)
445 {
446         switch (i) {  // prefer flyweights over new objects
447         case -12:
448                 return *const_cast<numeric *>(_num_12_p);
449         case -11:
450                 return *const_cast<numeric *>(_num_11_p);
451         case -10:
452                 return *const_cast<numeric *>(_num_10_p);
453         case -9:
454                 return *const_cast<numeric *>(_num_9_p);
455         case -8:
456                 return *const_cast<numeric *>(_num_8_p);
457         case -7:
458                 return *const_cast<numeric *>(_num_7_p);
459         case -6:
460                 return *const_cast<numeric *>(_num_6_p);
461         case -5:
462                 return *const_cast<numeric *>(_num_5_p);
463         case -4:
464                 return *const_cast<numeric *>(_num_4_p);
465         case -3:
466                 return *const_cast<numeric *>(_num_3_p);
467         case -2:
468                 return *const_cast<numeric *>(_num_2_p);
469         case -1:
470                 return *const_cast<numeric *>(_num_1_p);
471         case 0:
472                 return *const_cast<numeric *>(_num0_p);
473         case 1:
474                 return *const_cast<numeric *>(_num1_p);
475         case 2:
476                 return *const_cast<numeric *>(_num2_p);
477         case 3:
478                 return *const_cast<numeric *>(_num3_p);
479         case 4:
480                 return *const_cast<numeric *>(_num4_p);
481         case 5:
482                 return *const_cast<numeric *>(_num5_p);
483         case 6:
484                 return *const_cast<numeric *>(_num6_p);
485         case 7:
486                 return *const_cast<numeric *>(_num7_p);
487         case 8:
488                 return *const_cast<numeric *>(_num8_p);
489         case 9:
490                 return *const_cast<numeric *>(_num9_p);
491         case 10:
492                 return *const_cast<numeric *>(_num10_p);
493         case 11:
494                 return *const_cast<numeric *>(_num11_p);
495         case 12:
496                 return *const_cast<numeric *>(_num12_p);
497         default:
498                 return dynallocate<numeric>(i);
499         }
500 }
501         
502 basic & ex::construct_from_ulong(unsigned long i)
503 {
504         switch (i) {  // prefer flyweights over new objects
505         case 0:
506                 return *const_cast<numeric *>(_num0_p);
507         case 1:
508                 return *const_cast<numeric *>(_num1_p);
509         case 2:
510                 return *const_cast<numeric *>(_num2_p);
511         case 3:
512                 return *const_cast<numeric *>(_num3_p);
513         case 4:
514                 return *const_cast<numeric *>(_num4_p);
515         case 5:
516                 return *const_cast<numeric *>(_num5_p);
517         case 6:
518                 return *const_cast<numeric *>(_num6_p);
519         case 7:
520                 return *const_cast<numeric *>(_num7_p);
521         case 8:
522                 return *const_cast<numeric *>(_num8_p);
523         case 9:
524                 return *const_cast<numeric *>(_num9_p);
525         case 10:
526                 return *const_cast<numeric *>(_num10_p);
527         case 11:
528                 return *const_cast<numeric *>(_num11_p);
529         case 12:
530                 return *const_cast<numeric *>(_num12_p);
531         default:
532                 return dynallocate<numeric>(i);
533         }
534 }
535
536 basic & ex::construct_from_longlong(long long i)
537 {
538         if (i >= -12 && i <= 12) {
539                 return construct_from_int(static_cast<int>(i));
540         } else {
541                 return dynallocate<numeric>(i);
542         }
543 }
544
545 basic & ex::construct_from_ulonglong(unsigned long long i)
546 {
547         if (i <= 12) {
548                 return construct_from_uint(static_cast<unsigned>(i));
549         } else {
550                 return dynallocate<numeric>(i);
551         }
552 }
553
554 basic & ex::construct_from_double(double d)
555 {
556         return dynallocate<numeric>(d);
557 }
558
559 //////////
560 // static member variables
561 //////////
562
563 // none
564
565 //////////
566 // functions which are not member functions
567 //////////
568
569 // none
570
571 //////////
572 // global functions
573 //////////
574
575 // none
576
577
578 } // namespace GiNaC