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