GiNaC 1.8.7
ex.cpp
Go to the documentation of this file.
1
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
37namespace GiNaC {
38
40// other constructors
42
43// none (all inlined)
44
46// non-virtual functions in this class
48
49// public
50
56void ex::print(const print_context & c, unsigned level) const
57{
58 bp->print(c, level);
59}
60
62void ex::dbgprint() const
63{
64 bp->dbgprint();
65}
66
68void ex::dbgprinttree() const
69{
70 bp->dbgprinttree();
71}
72
75ex 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
88ex 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
97bool ex::match(const ex & pattern) const
98{
99 exmap repl_lst;
100 return bp->match(pattern, repl_lst);
101}
102
107bool 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
122ex 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))
135 }
138
139 return bp->subs(m, options);
140}
141
146ex ex::subs(const ex & e, unsigned options) const
147{
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))
157 else
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))
177 }
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
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
199{
200 size_t n = nops();
201 for (size_t i = 0; i < n; ++i)
203
204 accept(v);
205}
206
208ex & ex::let_op(size_t i)
209{
211 return bp->let_op(i);
212}
213
214ex & ex::operator[](const ex & index)
215{
217 return (*bp)[index];
218}
219
221{
223 return (*bp)[i];
224}
225
227ex 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
235ex 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
243bool 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
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
272{
274 bp.makewritable();
275 GINAC_ASSERT(bp->get_refcount() == 1);
276}
277
280void 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
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).
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();
346 GINAC_ASSERT(bp->get_refcount() == 0);
347 return bp;
348 }
349 }
350}
351
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
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
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
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
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
545basic & 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
555{
556 return dynallocate<numeric>(d);
557}
558
560// static member variables
562
563// none
564
566// functions which are not member functions
568
569// none
570
572// global functions
574
575// none
576
577
578} // namespace GiNaC
Interface to GiNaC's sums of expressions.
#define GINAC_ASSERT(X)
Assertion macro for checking invariances.
Definition: assertion.h:33
This class is the ABC (abstract base class) of GiNaC's class hierarchy.
Definition: basic.h:105
virtual ex eval() const
Perform automatic non-interruptive term rewriting rules.
Definition: basic.cpp:413
unsigned flags
of type status_flags
Definition: basic.h:302
virtual basic * duplicate() const
Create a clone of this object on the heap.
Definition: basic.h:131
Wrapper template for making GiNaC classes out of STL containers.
Definition: container.h:73
const_iterator end() const
Definition: container.h:240
const_iterator begin() const
Definition: container.h:239
size_t nops() const override
Number of operands/members.
Definition: container.h:118
Lightweight wrapper for GiNaC's symbolic objects.
Definition: ex.h:72
static basic & construct_from_ulonglong(unsigned long long i)
Definition: ex.cpp:545
static basic & construct_from_longlong(long long i)
Definition: ex.cpp:536
void traverse_preorder(visitor &v) const
Traverse expression tree with given visitor, preorder traversal.
Definition: ex.cpp:188
ex operator[](const ex &index) const
Definition: ex.h:137
static basic & construct_from_int(int i)
Definition: ex.cpp:352
static basic & construct_from_uint(unsigned int i)
Definition: ex.cpp:410
bool match(const ex &pattern) const
Check whether expression matches a specified pattern.
Definition: ex.cpp:97
bool is_polynomial(const ex &vars) const
Check whether expression is a polynomial.
Definition: ex.cpp:243
static ptr< basic > construct_from_basic(const basic &other)
Helper function for the ex-from-basic constructor.
Definition: ex.cpp:294
bool find(const ex &pattern, exset &found) const
Find all occurrences of a pattern.
Definition: ex.cpp:107
void accept(visitor &v) const
Definition: ex.h:166
ex diff(const symbol &s, unsigned nth=1) const
Compute partial derivative of an expression.
Definition: ex.cpp:88
ex expand(unsigned options=0) const
Expand an expression.
Definition: ex.cpp:75
static basic & construct_from_double(double d)
Definition: ex.cpp:554
ptr< basic > bp
pointer to basic object managed by this
Definition: ex.h:251
ex & let_op(size_t i)
Return modifiable operand/member at position i.
Definition: ex.cpp:208
bool is_zero_matrix() const
Check whether expression is zero or zero matrix.
Definition: ex.cpp:257
static basic & construct_from_ulong(unsigned long i)
Definition: ex.cpp:502
void share(const ex &other) const
Share equal objects between expressions.
Definition: ex.cpp:280
size_t nops() const
Definition: ex.h:135
static basic & construct_from_long(long i)
Definition: ex.cpp:444
ex subs(const exmap &m, unsigned options=0) const
Definition: ex.h:841
bool info(unsigned inf) const
Definition: ex.h:132
ex lhs() const
Left hand side of relational expression.
Definition: ex.cpp:227
bool is_zero() const
Definition: ex.h:213
void print(const print_context &c, unsigned level=0) const
Print expression to stream.
Definition: ex.cpp:56
void dbgprinttree() const
Little wrapper arount printtree to be called within a debugger.
Definition: ex.cpp:68
ex op(size_t i) const
Definition: ex.h:136
ex rhs() const
Right hand side of relational expression.
Definition: ex.cpp:235
ex evalm() const
Definition: ex.h:122
void dbgprint() const
Little wrapper arount print to be called within a debugger.
Definition: ex.cpp:62
void traverse_postorder(visitor &v) const
Traverse expression tree with given visitor, postorder traversal.
Definition: ex.cpp:198
void makewriteable()
Make this ex writable (if more than one ex handle the same basic) by unlinking the object and creatin...
Definition: ex.cpp:271
This class is a wrapper around CLN-numbers within the GiNaC class hierarchy.
Definition: numeric.h:82
Base class for print_contexts.
Definition: print.h:103
Class of (intrusively) reference-counted pointers that support copy-on-write semantics.
Definition: ptr.h:56
unsigned int get_refcount() const noexcept
Definition: ptr.h:41
@ expanded
.expand(0) has already done its job (other expand() options ignore this flag)
Definition: flags.h:204
@ evaluated
.eval() has already done its job
Definition: flags.h:203
@ dynallocated
heap-allocated (i.e. created by new if we want to be clever and bypass the stack,
Definition: flags.h:202
@ not_shareable
don't share instances of this object between different expressions unless explicitly asked to (used b...
Definition: flags.h:206
@ pattern_is_not_product
used internally by expairseq::subschildren()
Definition: flags.h:56
@ pattern_is_product
used internally by expairseq::subschildren()
Definition: flags.h:55
Basic CAS symbol.
Definition: symbol.h:39
Degenerate base class for visitors.
Definition: basic.h:97
Interface to GiNaC's light-weight expression handles.
unsigned options
Definition: factor.cpp:2475
size_t n
Definition: factor.cpp:1432
size_t c
Definition: factor.cpp:757
size_t r
Definition: factor.cpp:757
umodpoly lr[2]
Definition: factor.cpp:1428
mvec m
Definition: factor.cpp:758
Definition of GiNaC's lst.
Interface to symbolic matrices.
Interface to GiNaC's products of expressions.
Definition: add.cpp:38
const numeric * _num_3_p
Definition: utils.cpp:343
const numeric * _num_1_p
Definition: utils.cpp:351
const numeric * _num6_p
Definition: utils.cpp:404
std::map< ex, ex, ex_is_less > exmap
Definition: basic.h:50
const numeric * _num3_p
Definition: utils.cpp:392
std::set< ex, ex_is_less > exset
Definition: basic.h:49
const numeric * _num_10_p
Definition: utils.cpp:315
const numeric * _num_8_p
Definition: utils.cpp:323
const numeric * _num_5_p
Definition: utils.cpp:335
const numeric * _num_11_p
Definition: utils.cpp:311
const numeric * _num10_p
Definition: utils.cpp:420
const numeric * _num4_p
Definition: utils.cpp:396
const numeric * _num_12_p
Definition: utils.cpp:307
const numeric * _num_2_p
Definition: utils.cpp:347
const numeric * _num_9_p
Definition: utils.cpp:319
const numeric * _num2_p
Definition: utils.cpp:388
const numeric * _num11_p
Definition: utils.cpp:424
const numeric * _num7_p
Definition: utils.cpp:408
const numeric * _num12_p
Definition: utils.cpp:428
const numeric * _num_6_p
Definition: utils.cpp:331
const numeric * _num9_p
Definition: utils.cpp:416
const numeric * _num_7_p
Definition: utils.cpp:327
const numeric * _num1_p
Definition: utils.cpp:384
const numeric * _num8_p
Definition: utils.cpp:412
const numeric * _num_4_p
Definition: utils.cpp:339
const numeric * _num0_p
Definition: utils.cpp:367
const numeric * _num5_p
Definition: utils.cpp:400
Interface to GiNaC's non-commutative products of expressions.
Makes the interface to the underlying bignum package available.
Interface to GiNaC's symbolic exponentiation (basis^exponent).
Interface to relations between expressions.
Interface to several small and furry utilities needed within GiNaC but not of any interest to the use...

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