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