From: Chris Dams Date: Fri, 21 Apr 2006 16:16:01 +0000 (+0000) Subject: Added methods for taking real and imaginary parts. X-Git-Tag: release_1-4-0~93 X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=commitdiff_plain;h=690cd58cc13ad5052eb5851c573984965d0c40c1 Added methods for taking real and imaginary parts. --- diff --git a/doc/tutorial/ginac.texi b/doc/tutorial/ginac.texi index a6f802be..08fee762 100644 --- a/doc/tutorial/ginac.texi +++ b/doc/tutorial/ginac.texi @@ -79,20 +79,20 @@ framework for symbolic computation within the C++ programming language. @menu * Introduction:: GiNaC's purpose. -* A Tour of GiNaC:: A quick tour of the library. +* A tour of GiNaC:: A quick tour of the library. * Installation:: How to install the package. -* Basic Concepts:: Description of fundamental classes. -* Methods and Functions:: Algorithms for symbolic manipulations. +* Basic concepts:: Description of fundamental classes. +* Methods and functions:: Algorithms for symbolic manipulations. * Extending GiNaC:: How to extend the library. -* A Comparison With Other CAS:: Compares GiNaC to traditional CAS. -* Internal Structures:: Description of some internal structures. -* Package Tools:: Configuring packages to work with GiNaC. +* A comparison with other CAS:: Compares GiNaC to traditional CAS. +* Internal structures:: Description of some internal structures. +* Package tools:: Configuring packages to work with GiNaC. * Bibliography:: -* Concept Index:: +* Concept index:: @end menu -@node Introduction, A Tour of GiNaC, Top, Top +@node Introduction, A tour of GiNaC, Top, Top @c node-name, next, previous, up @chapter Introduction @cindex history of GiNaC @@ -154,7 +154,7 @@ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -@node A Tour of GiNaC, How to use it from within C++, Introduction, Top +@node A tour of GiNaC, How to use it from within C++, Introduction, Top @c node-name, next, previous, up @chapter A Tour of GiNaC @@ -168,7 +168,7 @@ leaves many open questions. @end menu -@node How to use it from within C++, What it can do for you, A Tour of GiNaC, A Tour of GiNaC +@node How to use it from within C++, What it can do for you, A tour of GiNaC, A tour of GiNaC @c node-name, next, previous, up @section How to use it from within C++ @@ -206,7 +206,7 @@ $ ./hello 355687428096000*x*y+20922789888000*y^2+6402373705728000*x^2 @end example -(@xref{Package Tools}, for tools that help you when creating a software +(@xref{Package tools}, for tools that help you when creating a software package that uses GiNaC.) @cindex Hermite polynomial @@ -256,7 +256,7 @@ the @command{ginsh}, a simple GiNaC interactive shell that provides a convenient window into GiNaC's capabilities. -@node What it can do for you, Installation, How to use it from within C++, A Tour of GiNaC +@node What it can do for you, Installation, How to use it from within C++, A tour of GiNaC @c node-name, next, previous, up @section What it can do for you @@ -638,7 +638,7 @@ subdirectories. It is therefore safe to go into any subdirectory @var{target} there in case something went wrong. -@node Installing GiNaC, Basic Concepts, Building GiNaC, Installation +@node Installing GiNaC, Basic concepts, Building GiNaC, Installation @c node-name, next, previous, up @section Installing GiNaC @cindex installation @@ -691,9 +691,9 @@ do it by hand since you now know where all the files went during installation.}. -@node Basic Concepts, Expressions, Installing GiNaC, Top +@node Basic concepts, Expressions, Installing GiNaC, Top @c node-name, next, previous, up -@chapter Basic Concepts +@chapter Basic concepts This chapter will describe the different fundamental objects that can be handled by GiNaC. But before doing so, it is worthwhile introducing you @@ -704,7 +704,7 @@ meta-class for storing all mathematical objects. * Expressions:: The fundamental GiNaC class. * Automatic evaluation:: Evaluation and canonicalization. * Error handling:: How the library reports errors. -* The Class Hierarchy:: Overview of GiNaC's classes. +* The class hierarchy:: Overview of GiNaC's classes. * Symbols:: Symbolic objects. * Numbers:: Numerical objects. * Constants:: Pre-defined constants. @@ -716,11 +716,11 @@ meta-class for storing all mathematical objects. * Matrices:: Matrices. * Indexed objects:: Handling indexed quantities. * Non-commutative objects:: Algebras with non-commutative products. -* Hash Maps:: A faster alternative to std::map<>. +* Hash maps:: A faster alternative to std::map<>. @end menu -@node Expressions, Automatic evaluation, Basic Concepts, Basic Concepts +@node Expressions, Automatic evaluation, Basic concepts, Basic concepts @c node-name, next, previous, up @section Expressions @cindex expression (class @code{ex}) @@ -742,7 +742,7 @@ ex MyEx5 = MyEx4 + 1; // similar to above Expressions are handles to other more fundamental objects, that often contain other expressions thus creating a tree of expressions -(@xref{Internal Structures}, for particular examples). Most methods on +(@xref{Internal structures}, for particular examples). Most methods on @code{ex} therefore run top-down through such an expression tree. For example, the method @code{has()} scans recursively for occurrences of something inside an expression. Thus, if you have declared @code{MyEx4} @@ -769,11 +769,11 @@ as @code{std::set}. Unsorted containers such as @code{std::vector<>} and @code{std::list<>} don't pose a problem. A @code{std::vector} works as expected. -@xref{Information About Expressions}, for more about comparing and ordering +@xref{Information about expressions}, for more about comparing and ordering expressions. -@node Automatic evaluation, Error handling, Expressions, Basic Concepts +@node Automatic evaluation, Error handling, Expressions, Basic concepts @c node-name, next, previous, up @section Automatic evaluation and canonicalization of expressions @cindex evaluation @@ -847,7 +847,7 @@ transform expressions, like @code{subs()} or @code{normal()}, automatically re-evaluate their results. -@node Error handling, The Class Hierarchy, Automatic evaluation, Basic Concepts +@node Error handling, The class hierarchy, Automatic evaluation, Basic concepts @c node-name, next, previous, up @section Error handling @cindex exceptions @@ -903,7 +903,7 @@ int main() @end example -@node The Class Hierarchy, Symbols, Error handling, Basic Concepts +@node The class hierarchy, Symbols, Error handling, Basic concepts @c node-name, next, previous, up @section The class hierarchy @@ -929,7 +929,7 @@ features. An example is @code{expairseq}, a container for a sequence of pairs each consisting of one expression and a number (@code{numeric}). What @emph{is} visible to the user are the derived classes @code{add} and @code{mul}, representing sums and products. @xref{Internal -Structures}, where these two classes are described in more detail. The +structures}, where these two classes are described in more detail. The following table shortly summarizes what kinds of mathematical objects are stored in the different classes: @@ -977,7 +977,7 @@ $\sin 2x$ @end cartouche -@node Symbols, Numbers, The Class Hierarchy, Basic Concepts +@node Symbols, Numbers, The class hierarchy, Basic concepts @c node-name, next, previous, up @section Symbols @cindex @code{symbol} (class) @@ -1128,7 +1128,7 @@ definitions. As we said, the names of symbols primarily serve for purposes of expression output. But there are actually two instances where GiNaC uses the names for identifying symbols: When constructing an expression from a string, and when -recreating an expression from an archive (@pxref{Input/Output}). +recreating an expression from an archive (@pxref{Input/output}). In addition to its name, a symbol may contain a special string that is used in LaTeX output: @@ -1137,7 +1137,7 @@ symbol x("x", "\\Box"); @end example This creates a symbol that is printed as "@code{x}" in normal output, but -as "@code{\Box}" in LaTeX code (@xref{Input/Output}, for more +as "@code{\Box}" in LaTeX code (@xref{Input/output}, for more information about the different output formats of expressions in GiNaC). GiNaC automatically creates proper LaTeX code for symbols having names of greek letters (@samp{alpha}, @samp{mu}, etc.). @@ -1147,12 +1147,12 @@ Symbols in GiNaC can't be assigned values. If you need to store results of calculations and give them a name, use C++ variables of type @code{ex}. If you want to replace a symbol in an expression with something else, you can invoke the expression's @code{.subs()} method -(@pxref{Substituting Expressions}). +(@pxref{Substituting expressions}). @cindex @code{realsymbol()} By default, symbols are expected to stand in for complex values, i.e. they live in the complex domain. As a consequence, operations like complex conjugation, -for example (@pxref{Complex Conjugation}), do @emph{not} evaluate if applied +for example (@pxref{Complex expressions}), do @emph{not} evaluate if applied to such symbols. Likewise @code{log(exp(x))} does not evaluate to @code{x}, because of the unknown imaginary part of @code{x}. On the other hand, if you are sure that your symbols will hold only real values, you @@ -1161,7 +1161,7 @@ the domain of the symbol. Instead of @code{symbol x("x");} you can write @code{realsymbol x("x");} to tell GiNaC that @code{x} stands in for real values. -@node Numbers, Constants, Symbols, Basic Concepts +@node Numbers, Constants, Symbols, Basic concepts @c node-name, next, previous, up @section Numbers @cindex @code{numeric} (class) @@ -1511,7 +1511,7 @@ rational number will return a floating-point approximation. Both part of complex numbers. -@node Constants, Fundamental containers, Numbers, Basic Concepts +@node Constants, Fundamental containers, Numbers, Basic concepts @c node-name, next, previous, up @section Constants @cindex @code{constant} (class) @@ -1541,7 +1541,7 @@ The predefined known constants are: @end cartouche -@node Fundamental containers, Lists, Constants, Basic Concepts +@node Fundamental containers, Lists, Constants, Basic concepts @c node-name, next, previous, up @section Sums, products and powers @cindex polynomial @@ -1612,7 +1612,7 @@ and safe simplifications are carried out like transforming @code{3*x+4-x} to @code{2*x+4}. -@node Lists, Mathematical functions, Fundamental containers, Basic Concepts +@node Lists, Mathematical functions, Fundamental containers, Basic concepts @c node-name, next, previous, up @section Lists of expressions @cindex @code{lst} (class) @@ -1777,7 +1777,7 @@ elements with @code{unique()}: @end example -@node Mathematical functions, Relations, Lists, Basic Concepts +@node Mathematical functions, Relations, Lists, Basic concepts @c node-name, next, previous, up @section Mathematical functions @cindex @code{function} (class) @@ -1786,7 +1786,7 @@ elements with @code{unique()}: There are quite a number of useful functions hard-wired into GiNaC. For instance, all trigonometric and hyperbolic functions are implemented -(@xref{Built-in Functions}, for a complete list). +(@xref{Built-in functions}, for a complete list). These functions (better called @emph{pseudofunctions}) are all objects of class @code{function}. They accept one or more expressions as @@ -1829,7 +1829,7 @@ point number of class @code{numeric} you should call wrapped inside an @code{ex}. -@node Relations, Integrals, Mathematical functions, Basic Concepts +@node Relations, Integrals, Mathematical functions, Basic concepts @c node-name, next, previous, up @section Relations @cindex @code{relational} (class) @@ -1855,7 +1855,7 @@ conversion from @code{relational} to @code{bool} takes place. Note, however, that @code{==} here does not perform any simplifications, hence @code{expand()} must be called explicitly. -@node Integrals, Matrices, Relations, Basic Concepts +@node Integrals, Matrices, Relations, Basic concepts @c node-name, next, previous, up @section Integrals @cindex @code{integral} (class) @@ -1916,7 +1916,7 @@ respectively calling @code{.op(0)}, @code{.op(1)}, @code{.op(2)}, and as expected. Note that it makes no sense to differentiate an integral with respect to the integration variable. -@node Matrices, Indexed objects, Integrals, Basic Concepts +@node Matrices, Indexed objects, Integrals, Basic concepts @c node-name, next, previous, up @section Matrices @cindex @code{matrix} (class) @@ -2180,7 +2180,7 @@ contain some of the indeterminates from @code{vars}. If the system is overdetermined, an exception is thrown. -@node Indexed objects, Non-commutative objects, Matrices, Basic Concepts +@node Indexed objects, Non-commutative objects, Matrices, Basic concepts @c node-name, next, previous, up @section Indexed objects @@ -2329,7 +2329,7 @@ bool idx::is_dim_symbolic(); for checking whether the value and dimension are numeric or symbolic (non-numeric). Using the @code{info()} method of an index (see @ref{Information -About Expressions}) returns information about the index value. +about expressions}) returns information about the index value. @cindex @code{varidx} (class) If you need co- and contravariant indices, use the @code{varidx} class: @@ -2420,7 +2420,7 @@ and the same or opposite variance. Sometimes you will want to substitute one symbolic index with another symbolic or numeric index, for example when calculating one specific element of a tensor expression. This is done with the @code{.subs()} method, as it -is done for symbols (see @ref{Substituting Expressions}). +is done for symbols (see @ref{Substituting expressions}). You have two possibilities here. You can either substitute the whole index by another index or expression: @@ -2956,7 +2956,7 @@ one form for @samp{F} and explicitly multiply it with a matrix representation of the metric tensor. -@node Non-commutative objects, Hash Maps, Indexed objects, Basic Concepts +@node Non-commutative objects, Hash maps, Indexed objects, Basic concepts @c node-name, next, previous, up @section Non-commutative objects @@ -3717,7 +3717,7 @@ example: @end example -@node Hash Maps, Methods and Functions, Non-commutative objects, Basic Concepts +@node Hash maps, Methods and functions, Non-commutative objects, Basic concepts @c node-name, next, previous, up @section Hash Maps @cindex hash maps @@ -3753,9 +3753,9 @@ table @end itemize -@node Methods and Functions, Information About Expressions, Hash Maps, Top +@node Methods and functions, Information about expressions, Hash maps, Top @c node-name, next, previous, up -@chapter Methods and Functions +@chapter Methods and functions @cindex polynomial In this chapter the most important algorithms provided by GiNaC will be @@ -3794,26 +3794,26 @@ method on class @code{ex} and sometimes calling a function cannot be avoided. @menu -* Information About Expressions:: -* Numerical Evaluation:: -* Substituting Expressions:: -* Pattern Matching and Advanced Substitutions:: -* Applying a Function on Subexpressions:: -* Visitors and Tree Traversal:: -* Polynomial Arithmetic:: Working with polynomials. -* Rational Expressions:: Working with rational functions. -* Symbolic Differentiation:: -* Series Expansion:: Taylor and Laurent expansion. +* Information about expressions:: +* Numerical evaluation:: +* Substituting expressions:: +* Pattern matching and advanced substitutions:: +* Applying a function on subexpressions:: +* Visitors and tree traversal:: +* Polynomial arithmetic:: Working with polynomials. +* Rational expressions:: Working with rational functions. +* Symbolic differentiation:: +* Series expansion:: Taylor and Laurent expansion. * Symmetrization:: -* Built-in Functions:: List of predefined mathematical functions. +* Built-in functions:: List of predefined mathematical functions. * Multiple polylogarithms:: -* Complex Conjugation:: -* Solving Linear Systems of Equations:: -* Input/Output:: Input and output of expressions. +* Complex expressions:: +* Solving linear systems of equations:: +* Input/output:: Input and output of expressions. @end menu -@node Information About Expressions, Numerical Evaluation, Methods and Functions, Methods and Functions +@node Information about expressions, Numerical evaluation, Methods and functions, Methods and functions @c node-name, next, previous, up @section Getting information about expressions @@ -3840,7 +3840,7 @@ unsigned ex::return_type_tinfo() const; When the test made by @code{is_a()} returns true, it is safe to call one of the functions @code{ex_to()}, where @code{T} is one of the -class names (@xref{The Class Hierarchy}, for a list of all classes). For +class names (@xref{The class hierarchy}, for a list of all classes). For example, assuming @code{e} is an @code{ex}: @example @@ -3854,7 +3854,7 @@ example, assuming @code{e} is an @code{ex}: @code{is_a(e)} allows you to check whether the top-level object of an expression @samp{e} is an instance of the GiNaC class @samp{T} -(@xref{The Class Hierarchy}, for a list of all classes). This is most useful, +(@xref{The class hierarchy}, for a list of all classes). This is most useful, e.g., for checking whether an expression is a number, a sum, or a product: @example @@ -4170,7 +4170,7 @@ if @code{*this} sorts before @code{other}, and @math{1} if @code{*this} sorts after @code{other}. -@node Numerical Evaluation, Substituting Expressions, Information About Expressions, Methods and Functions +@node Numerical evaluation, Substituting expressions, Information about expressions, Methods and functions @c node-name, next, previous, up @section Numerical evaluation @cindex @code{evalf()} @@ -4210,7 +4210,7 @@ call @code{evalf()} followed by @code{numeric::to_double()}, like this: @end example -@node Substituting Expressions, Pattern Matching and Advanced Substitutions, Numerical Evaluation, Methods and Functions +@node Substituting expressions, Pattern matching and advanced substitutions, Numerical evaluation, Methods and functions @c node-name, next, previous, up @section Substituting expressions @cindex @code{subs()} @@ -4283,7 +4283,7 @@ The optional last argument to @code{subs()} is a combination of large @code{subs()} operations significantly faster if you are not using patterns. The second option, @code{subs_options::algebraic} enables algebraic substitutions in products and powers. -@ref{Pattern Matching and Advanced Substitutions}, for more information +@ref{Pattern matching and advanced substitutions}, for more information about patterns and algebraic substitutions. The third option, @code{subs_options::no_index_renaming} disables the feature that dummy indices are renamed if the subsitution could give a result in which a @@ -4317,7 +4317,7 @@ A more powerful form of substitution using wildcards is described in the next section. -@node Pattern Matching and Advanced Substitutions, Applying a Function on Subexpressions, Substituting Expressions, Methods and Functions +@node Pattern matching and advanced substitutions, Applying a function on subexpressions, Substituting expressions, Methods and functions @c node-name, next, previous, up @section Pattern matching and advanced substitutions @cindex @code{wildcard} (class) @@ -4610,7 +4610,7 @@ return @code{x^(-1)*c^2*z}. Note that this only works for multiplications and not for locating @code{x+y} within @code{x+y+z}. -@node Applying a Function on Subexpressions, Visitors and Tree Traversal, Pattern Matching and Advanced Substitutions, Methods and Functions +@node Applying a function on subexpressions, Visitors and tree traversal, Pattern matching and advanced substitutions, Methods and functions @c node-name, next, previous, up @section Applying a function on subexpressions @cindex tree traversal @@ -4755,7 +4755,7 @@ argument. You can not use functions like @samp{diff()}, @samp{op()}, @end example -@node Visitors and Tree Traversal, Polynomial Arithmetic, Applying a Function on Subexpressions, Methods and Functions +@node Visitors and tree traversal, Polynomial arithmetic, Applying a function on subexpressions, Methods and functions @c node-name, next, previous, up @section Visitors and tree traversal @cindex tree traversal @@ -4977,7 +4977,7 @@ lst gather_indices(const ex & e) @end example -@node Polynomial Arithmetic, Rational Expressions, Visitors and Tree Traversal, Methods and Functions +@node Polynomial arithmetic, Rational expressions, Visitors and tree traversal, Methods and functions @c node-name, next, previous, up @section Polynomial arithmetic @@ -5351,7 +5351,7 @@ Note also, how factors with the same exponents are not fully factorized with this method. -@node Rational Expressions, Symbolic Differentiation, Polynomial Arithmetic, Methods and Functions +@node Rational expressions, Symbolic differentiation, Polynomial arithmetic, Methods and functions @c node-name, next, previous, up @section Rational expressions @@ -5477,7 +5477,7 @@ The following more useful example will print @samp{sin(x)-cos(x)}: @end example -@node Symbolic Differentiation, Series Expansion, Rational Expressions, Methods and Functions +@node Symbolic differentiation, Series expansion, Rational expressions, Methods and functions @c node-name, next, previous, up @section Symbolic differentiation @cindex differentiation @@ -5543,7 +5543,7 @@ When you run it, it produces the sequence @code{1}, @code{-1}, @code{5}, @code{i} by two since all odd Euler numbers vanish anyways. -@node Series Expansion, Symmetrization, Symbolic Differentiation, Methods and Functions +@node Series expansion, Symmetrization, Symbolic differentiation, Methods and functions @c node-name, next, previous, up @section Series expansion @cindex @code{series()} @@ -5656,7 +5656,7 @@ program, it will type out: @end example -@node Symmetrization, Built-in Functions, Series Expansion, Methods and Functions +@node Symmetrization, Built-in functions, Series expansion, Methods and functions @c node-name, next, previous, up @section Symmetrization @cindex @code{symmetrize()} @@ -5702,7 +5702,7 @@ almost any kind of object (anything that is @code{subs()}able): @} @end example -@node Built-in Functions, Multiple polylogarithms, Symmetrization, Methods and Functions +@node Built-in functions, Multiple polylogarithms, Symmetrization, Methods and functions @c node-name, next, previous, up @section Predefined mathematical functions @c @@ -5724,7 +5724,12 @@ GiNaC contains the following predefined mathematical functions: @cindex @code{conjugate()} @item @code{conjugate(x)} @tab complex conjugation -@cindex @code{conjugate()} +@cindex @code{real_part()} +@item @code{real_part(x)} +@tab real part +@cindex @code{imag_part()} +@item @code{imag_part(x)} +@tab imaginary part @item @code{sqrt(x)} @tab square root (not a GiNaC function, rather an alias for @code{pow(x, numeric(1, 2))}) @cindex @code{sqrt()} @@ -5841,7 +5846,7 @@ serious CAS. It is to be expected that future revisions of the C++ standard incorporate these functions in the complex domain in a manner compatible with C99. -@node Multiple polylogarithms, Complex Conjugation, Built-in Functions, Methods and Functions +@node Multiple polylogarithms, Complex expressions, Built-in functions, Methods and functions @c node-name, next, previous, up @subsection Multiple polylogarithms @@ -6001,21 +6006,32 @@ J.Borwein, D.Bradley, D.Broadhurst, P.Lisonek, Trans.Amer.Math.Soc. 353/3 (2001) @cite{Numerical Evaluation of Multiple Polylogarithms}, J.Vollinga, S.Weinzierl, hep-ph/0410259 -@node Complex Conjugation, Solving Linear Systems of Equations, Multiple polylogarithms, Methods and Functions +@node Complex expressions, Solving linear systems of equations, Multiple polylogarithms, Methods and functions @c node-name, next, previous, up -@section Complex conjugation +@section Complex expressions @c @cindex @code{conjugate()} -The method +For dealing with complex expressions there are the methods @example ex ex::conjugate(); +ex ex::real_part(); +ex ex::imag_part(); @end example -returns the complex conjugate of the expression. For all built-in functions and objects the -conjugation gives the expected results: +that return respectively the complex conjugate, the real part and the +imaginary part of an expression. Complex conjugation works as expected +for all built-in functinos and objects. Taking real and imaginary +parts has not yet been implemented for all built-in functions. In cases where +it is not known how to conjugate or take a real/imaginary part one +of the functions @code{conjugate}, @code{real_part} or @code{imag_part} +is returned. For instance, in case of a complex symbol @code{x} +(symbols are complex by default), one could not simplify +@code{conjugate(x)}. In the case of strings of gamma matrices, +the @code{conjugate} method takes the Dirac conjugate. +For example, @example @{ varidx a(symbol("a"), 4), b(symbol("b"), 4); @@ -6029,13 +6045,14 @@ conjugation gives the expected results: @} @end example -For symbols in the complex domain the conjugation can not be evaluated and the GiNaC function -@code{conjugate} is returned. GiNaC functions conjugate by applying the conjugation to their -arguments. This is the default strategy. If you want to define your own functions and want to -change this behavior, you have to supply a specialized conjugation method for your function -(see @ref{Symbolic functions} and the GiNaC source-code for @code{abs} as an example). +If you declare your own GiNaC functions, then they will conjugate themselves +by conjugating their arguments. This is the default strategy. If you want to +change this behavior, you have to supply a specialized conjugation method +for your function (see @ref{Symbolic functions} and the GiNaC source-code +for @code{abs} as an example). Also, specialized methods can be provided +to take real and imaginary parts of user-defined functions. -@node Solving Linear Systems of Equations, Input/Output, Complex Conjugation, Methods and Functions +@node Solving linear systems of equations, Input/output, Complex expressions, Methods and functions @c node-name, next, previous, up @section Solving linear systems of equations @cindex @code{lsolve()} @@ -6051,7 +6068,7 @@ ex lsolve(const ex & eqns, const ex & symbols, Here, @code{eqns} is a @code{lst} of equalities (i.e. class @code{relational}) while @code{symbols} is a @code{lst} of -indeterminates. (@xref{The Class Hierarchy}, for an exposition of class +indeterminates. (@xref{The class hierarchy}, for an exposition of class @code{lst}). It returns the @code{lst} of solutions as an expression. As an example, @@ -6076,7 +6093,7 @@ to @code{lsolve()}: it accepts the same parameters as around that method. -@node Input/Output, Extending GiNaC, Solving Linear Systems of Equations, Methods and Functions +@node Input/output, Extending GiNaC, Solving linear systems of equations, Methods and functions @c node-name, next, previous, up @section Input and output of expressions @cindex I/O @@ -6518,7 +6535,7 @@ Be warned, however, that the set of properties and their meaning for each class may change between GiNaC versions. -@node Extending GiNaC, What does not belong into GiNaC, Input/Output, Top +@node Extending GiNaC, What does not belong into GiNaC, Input/output, Top @c node-name, next, previous, up @chapter Extending GiNaC @@ -6876,7 +6893,7 @@ code for the @code{psi()} function (@file{inifcns.h} and @section GiNaC's expression output system GiNaC allows the output of expressions in a variety of different formats -(@pxref{Input/Output}). This section will explain how expression output +(@pxref{Input/output}). This section will explain how expression output is implemented internally, and how to define your own output formats or change the output format of built-in algebraic objects. You will also want to read this section if you plan to write your own algebraic classes or @@ -7558,7 +7575,7 @@ Note that the unarchiving constructor is @code{sprod::structure} and not @code{sprod::unarchive()} function. -@node Adding classes, A Comparison With Other CAS, Structures, Extending GiNaC +@node Adding classes, A comparison with other CAS, Structures, Extending GiNaC @c node-name, next, previous, up @section Adding classes @@ -8066,7 +8083,7 @@ should become a need. That's it. May the source be with you! -@node A Comparison With Other CAS, Advantages, Adding classes, Top +@node A comparison with other CAS, Advantages, Adding classes, Top @c node-name, next, previous, up @chapter A Comparison With Other CAS @cindex advocacy @@ -8082,7 +8099,7 @@ disadvantages over these systems. * Why C++?:: Attractiveness of C++. @end menu -@node Advantages, Disadvantages, A Comparison With Other CAS, A Comparison With Other CAS +@node Advantages, Disadvantages, A comparison with other CAS, A comparison with other CAS @c node-name, next, previous, up @section Advantages @@ -8162,7 +8179,7 @@ speed with other CAS. @end itemize -@node Disadvantages, Why C++?, Advantages, A Comparison With Other CAS +@node Disadvantages, Why C++?, Advantages, A comparison with other CAS @c node-name, next, previous, up @section Disadvantages @@ -8197,7 +8214,7 @@ yet ANSI compliant, support all needed features. @end itemize -@node Why C++?, Internal Structures, Disadvantages, A Comparison With Other CAS +@node Why C++?, Internal structures, Disadvantages, A comparison with other CAS @c node-name, next, previous, up @section Why C++? @@ -8214,16 +8231,16 @@ Furthermore, the main developers are more familiar with C++ than with any other programming language. -@node Internal Structures, Expressions are reference counted, Why C++? , Top +@node Internal structures, Expressions are reference counted, Why C++? , Top @c node-name, next, previous, up -@appendix Internal Structures +@appendix Internal structures @menu * Expressions are reference counted:: * Internal representation of products and sums:: @end menu -@node Expressions are reference counted, Internal representation of products and sums, Internal Structures, Internal Structures +@node Expressions are reference counted, Internal representation of products and sums, Internal structures, Internal structures @c node-name, next, previous, up @appendixsection Expressions are reference counted @@ -8312,7 +8329,7 @@ Marshall Cline. Chapter 16 covers this issue and presents an implementation which is pretty close to the one in GiNaC. -@node Internal representation of products and sums, Package Tools, Expressions are reference counted, Internal Structures +@node Internal representation of products and sums, Package tools, Expressions are reference counted, Internal structures @c node-name, next, previous, up @appendixsection Internal representation of products and sums @@ -8380,9 +8397,9 @@ expansion and the like are reimplemented for @code{add} and @code{mul}, but the data structure is inherited from @code{expairseq}. -@node Package Tools, ginac-config, Internal representation of products and sums, Top +@node Package tools, ginac-config, Internal representation of products and sums, Top @c node-name, next, previous, up -@appendix Package Tools +@appendix Package tools If you are creating a software package that uses the GiNaC library, setting the correct command line options for the compiler and linker @@ -8394,7 +8411,7 @@ can be difficult. GiNaC includes two tools to make this process easier. @end menu -@node ginac-config, AM_PATH_GINAC, Package Tools, Package Tools +@node ginac-config, AM_PATH_GINAC, Package tools, Package tools @c node-name, next, previous, up @section @command{ginac-config} @cindex ginac-config @@ -8441,7 +8458,7 @@ Not only is the form using @command{ginac-config} easier to type, it will work on any system, no matter how GiNaC was configured. -@node AM_PATH_GINAC, Configure script options, ginac-config, Package Tools +@node AM_PATH_GINAC, Configure script options, ginac-config, Package tools @c node-name, next, previous, up @section @samp{AM_PATH_GINAC} @cindex AM_PATH_GINAC @@ -8654,7 +8671,7 @@ $ make install @end example -@node Bibliography, Concept Index, Example package, Top +@node Bibliography, Concept index, Example package, Top @c node-name, next, previous, up @appendix Bibliography @@ -8699,9 +8716,9 @@ ISBN 3-540-66572-2, 2001, Springer, Heidelberg @end itemize -@node Concept Index, , Bibliography, Top +@node Concept index, , Bibliography, Top @c node-name, next, previous, up -@unnumbered Concept Index +@unnumbered Concept index @printindex cp diff --git a/ginac/add.cpp b/ginac/add.cpp index acced780..9c314ee6 100644 --- a/ginac/add.cpp +++ b/ginac/add.cpp @@ -424,6 +424,36 @@ ex add::conjugate() const return *this; } +ex add::real_part() const +{ + epvector v; + v.reserve(seq.size()); + for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) + if ((i->coeff).info(info_flags::real)) + v.push_back(expair((i->rest).real_part(), i->coeff)); + else { + ex rp=recombine_pair_to_ex(*i).real_part(); + v.push_back(split_ex_to_pair(rp)); + } + return (new add(v, overall_coeff.real_part())) + -> setflag(status_flags::dynallocated); +} + +ex add::imag_part() const +{ + epvector v; + v.reserve(seq.size()); + for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) + if ((i->coeff).info(info_flags::real)) + v.push_back(expair((i->rest).imag_part(), i->coeff)); + else { + ex ip=recombine_pair_to_ex(*i).imag_part(); + v.push_back(split_ex_to_pair(ip)); + } + return (new add(v, overall_coeff.imag_part())) + -> setflag(status_flags::dynallocated); +} + ex add::eval_ncmul(const exvector & v) const { if (seq.empty()) diff --git a/ginac/add.h b/ginac/add.h index 6d87f6bc..cee93aae 100644 --- a/ginac/add.h +++ b/ginac/add.h @@ -58,6 +58,8 @@ public: ex smod(const numeric &xi) const; numeric max_coefficient() const; ex conjugate() const; + ex real_part() const; + ex imag_part() const; exvector get_free_indices() const; ex eval_ncmul(const exvector & v) const; protected: diff --git a/ginac/basic.cpp b/ginac/basic.cpp index a3c727be..f86483e4 100644 --- a/ginac/basic.cpp +++ b/ginac/basic.cpp @@ -38,6 +38,7 @@ #include "wildcard.h" #include "archive.h" #include "utils.h" +#include "inifcns.h" namespace GiNaC { @@ -711,6 +712,16 @@ ex basic::conjugate() const return *this; } +ex basic::real_part() const +{ + return real_part_function(*this).hold(); +} + +ex basic::imag_part() const +{ + return imag_part_function(*this).hold(); +} + ex basic::eval_ncmul(const exvector & v) const { return hold_ncmul(v); diff --git a/ginac/basic.h b/ginac/basic.h index 6b117cc9..b08ad669 100644 --- a/ginac/basic.h +++ b/ginac/basic.h @@ -215,8 +215,10 @@ public: virtual unsigned return_type() const; virtual tinfo_t return_type_tinfo() const; - // complex conjugation + // functions for complex expressions virtual ex conjugate() const; + virtual ex real_part() const; + virtual ex imag_part() const; // functions that should be called from class ex only protected: diff --git a/ginac/constant.cpp b/ginac/constant.cpp index 8ae372be..cff955a9 100644 --- a/ginac/constant.cpp +++ b/ginac/constant.cpp @@ -29,6 +29,7 @@ #include "ex.h" #include "archive.h" #include "utils.h" +#include "inifcns.h" namespace GiNaC { @@ -161,6 +162,27 @@ bool constant::is_polynomial(const ex & var) const return true; } +ex constant::conjugate() const +{ + if ( domain == domain::real ) + return *this; + return conjugate_function(*this).hold(); +} + +ex constant::real_part() const +{ + if ( domain == domain::real ) + return *this; + return real_part_function(*this).hold(); +} + +ex constant::imag_part() const +{ + if ( domain == domain::real ) + return 0; + return imag_part_function(*this).hold(); +} + // protected /** Implementation of ex::diff() for a constant always returns 0. diff --git a/ginac/constant.h b/ginac/constant.h index 4b4a5e45..5ba32987 100644 --- a/ginac/constant.h +++ b/ginac/constant.h @@ -51,6 +51,9 @@ public: bool info(unsigned inf) const; ex evalf(int level = 0) const; bool is_polynomial(const ex & var) const; + ex conjugate() const; + ex real_part() const; + ex imag_part() const; protected: ex derivative(const symbol & s) const; bool is_equal_same_type(const basic & other) const; diff --git a/ginac/container.h b/ginac/container.h index 5774d5ac..28cf05e4 100644 --- a/ginac/container.h +++ b/ginac/container.h @@ -394,6 +394,28 @@ protected: return *this; } + ex real_part() const + { + STLT cont; + reserve(cont, nops()); + const_iterator b = begin(); + const_iterator e = end(); + for(const_iterator i=b; i!=e; ++i) + cont.push_back(i->real_part()); + return thiscontainer(cont); + } + + ex imag_part() const + { + STLT cont; + reserve(cont, nops()); + const_iterator b = begin(); + const_iterator e = end(); + for(const_iterator i=b; i!=e; ++i) + cont.push_back(i->imag_part()); + return thiscontainer(cont); + } + bool is_equal_same_type(const basic & other) const; // new virtual functions which can be overridden by derived classes diff --git a/ginac/ex.h b/ginac/ex.h index c23336ba..030046c5 100644 --- a/ginac/ex.h +++ b/ginac/ex.h @@ -134,8 +134,10 @@ public: ex lhs() const; ex rhs() const; - // complex conjugation + // function for complex expressions ex conjugate() const { return bp->conjugate(); } + ex real_part() const { return bp->real_part(); } + ex imag_part() const { return bp->imag_part(); } // pattern matching bool has(const ex & pattern, unsigned options = 0) const { return bp->has(pattern, options); } @@ -685,6 +687,12 @@ inline ex expand(const ex & thisex, unsigned options = 0) inline ex conjugate(const ex & thisex) { return thisex.conjugate(); } +inline ex real_part(const ex & thisex) +{ return thisex.real_part(); } + +inline ex imag_part(const ex & thisex) +{ return thisex.imag_part(); } + inline bool has(const ex & thisex, const ex & pattern, unsigned options = 0) { return thisex.has(pattern, options); } diff --git a/ginac/function.pl b/ginac/function.pl index e3c10f1e..43543462 100755 --- a/ginac/function.pl +++ b/ginac/function.pl @@ -79,6 +79,14 @@ $typedef_conjugate_funcp=generate( 'typedef ex (* conjugate_funcp_${N})(${SEQ1});'."\n", 'const ex &','',''); +$typedef_real_part_funcp=generate( +'typedef ex (* real_part_funcp_${N})(${SEQ1});'."\n", +'const ex &','',''); + +$typedef_imag_part_funcp=generate( +'typedef ex (* imag_part_funcp_${N})(${SEQ1});'."\n", +'const ex &','',''); + $typedef_derivative_funcp=generate( 'typedef ex (* derivative_funcp_${N})(${SEQ1}, unsigned);'."\n", 'const ex &','',''); @@ -101,6 +109,10 @@ $evalf_func_interface=generate(' function_options & evalf_func(evalf_funcp_${ $conjugate_func_interface=generate(' function_options & conjugate_func(conjugate_funcp_${N} d);'."\n",'','',''); +$real_part_func_interface=generate(' function_options & real_part_func(real_part_funcp_${N} d);'."\n",'','',''); + +$imag_part_func_interface=generate(' function_options & imag_part_func(imag_part_funcp_${N} d);'."\n",'','',''); + $derivative_func_interface=generate(' function_options & derivative_func(derivative_funcp_${N} d);'."\n",'','',''); $power_func_interface=generate(' function_options & power_func(power_funcp_${N} d);'."\n",'','',''); @@ -149,6 +161,18 @@ $conjugate_switch_statement=generate( return ((conjugate_funcp_${N})(opt.conjugate_f))(${SEQ1}); END_OF_DIFF_SWITCH_STATEMENT +$real_part_switch_statement=generate( + <<'END_OF_DIFF_SWITCH_STATEMENT','seq[${N}-1]','',''); + case ${N}: + return ((real_part_funcp_${N})(opt.real_part_f))(${SEQ1}); +END_OF_DIFF_SWITCH_STATEMENT + +$imag_part_switch_statement=generate( + <<'END_OF_DIFF_SWITCH_STATEMENT','seq[${N}-1]','',''); + case ${N}: + return ((imag_part_funcp_${N})(opt.imag_part_f))(${SEQ1}); +END_OF_DIFF_SWITCH_STATEMENT + $diff_switch_statement=generate( <<'END_OF_DIFF_SWITCH_STATEMENT','seq[${N}-1]','',''); case ${N}: @@ -209,6 +233,26 @@ function_options & function_options::conjugate_func(conjugate_funcp_${N} c) } END_OF_CONJUGATE_FUNC_IMPLEMENTATION +$real_part_func_implementation=generate( + <<'END_OF_REAL_PART_FUNC_IMPLEMENTATION','','',''); +function_options & function_options::real_part_func(real_part_funcp_${N} c) +{ + test_and_set_nparams(${N}); + real_part_f = real_part_funcp(c); + return *this; +} +END_OF_REAL_PART_FUNC_IMPLEMENTATION + +$imag_part_func_implementation=generate( + <<'END_OF_IMAG_PART_FUNC_IMPLEMENTATION','','',''); +function_options & function_options::imag_part_func(imag_part_funcp_${N} c) +{ + test_and_set_nparams(${N}); + imag_part_f = imag_part_funcp(c); + return *this; +} +END_OF_IMAG_PART_FUNC_IMPLEMENTATION + $derivative_func_implementation=generate( <<'END_OF_DERIVATIVE_FUNC_IMPLEMENTATION','','',''); function_options & function_options::derivative_func(derivative_funcp_${N} d) @@ -293,6 +337,8 @@ class symmetry; typedef ex (* eval_funcp)(); typedef ex (* evalf_funcp)(); typedef ex (* conjugate_funcp)(); +typedef ex (* real_part_funcp)(); +typedef ex (* imag_part_funcp)(); typedef ex (* derivative_funcp)(); typedef ex (* power_funcp)(); typedef ex (* series_funcp)(); @@ -302,6 +348,8 @@ typedef void (* print_funcp)(); $typedef_eval_funcp $typedef_evalf_funcp $typedef_conjugate_funcp +$typedef_real_part_funcp +$typedef_imag_part_funcp $typedef_derivative_funcp $typedef_power_funcp $typedef_series_funcp @@ -313,6 +361,8 @@ $typedef_print_funcp typedef ex (* eval_funcp_exvector)(const exvector &); typedef ex (* evalf_funcp_exvector)(const exvector &); typedef ex (* conjugate_funcp_exvector)(const exvector &); +typedef ex (* real_part_funcp_exvector)(const exvector &); +typedef ex (* imag_part_funcp_exvector)(const exvector &); typedef ex (* derivative_funcp_exvector)(const exvector &, unsigned); typedef ex (* power_funcp_exvector)(const exvector &, const ex &); typedef ex (* series_funcp_exvector)(const exvector &, const relational &, int, unsigned); @@ -337,6 +387,8 @@ public: $eval_func_interface $evalf_func_interface $conjugate_func_interface +$real_part_func_interface +$imag_part_func_interface $derivative_func_interface $power_func_interface $series_func_interface @@ -345,6 +397,8 @@ $print_func_interface function_options & eval_func(eval_funcp_exvector e); function_options & evalf_func(evalf_funcp_exvector ef); function_options & conjugate_func(conjugate_funcp_exvector d); + function_options & real_part_func(real_part_funcp_exvector d); + function_options & imag_part_func(imag_part_funcp_exvector d); function_options & derivative_func(derivative_funcp_exvector d); function_options & power_func(power_funcp_exvector d); function_options & series_func(series_funcp_exvector s); @@ -380,6 +434,8 @@ protected: eval_funcp eval_f; evalf_funcp evalf_f; conjugate_funcp conjugate_f; + real_part_funcp real_part_f; + imag_part_funcp imag_part_f; derivative_funcp derivative_f; power_funcp power_f; series_funcp series_f; @@ -399,6 +455,8 @@ protected: bool eval_use_exvector_args; bool evalf_use_exvector_args; bool conjugate_use_exvector_args; + bool real_part_use_exvector_args; + bool imag_part_use_exvector_args; bool derivative_use_exvector_args; bool power_use_exvector_args; bool series_use_exvector_args; @@ -454,6 +512,8 @@ public: ex thiscontainer(const exvector & v) const; ex thiscontainer(std::auto_ptr vp) const; ex conjugate() const; + ex real_part() const; + ex imag_part() const; protected: ex derivative(const symbol & s) const; bool is_equal_same_type(const basic & other) const; @@ -581,12 +641,15 @@ void function_options::initialize() { set_name("unnamed_function", "\\\\mbox{unnamed}"); nparams = 0; - eval_f = evalf_f = conjugate_f = derivative_f = power_f = series_f = 0; + eval_f = evalf_f = real_part_f = imag_part_f = conjugate_f = derivative_f + = power_f = series_f = 0; evalf_params_first = true; use_return_type = false; eval_use_exvector_args = false; evalf_use_exvector_args = false; conjugate_use_exvector_args = false; + real_part_use_exvector_args = false; + imag_part_use_exvector_args = false; derivative_use_exvector_args = false; power_use_exvector_args = false; series_use_exvector_args = false; @@ -617,6 +680,8 @@ function_options & function_options::latex_name(std::string const & tn) $eval_func_implementation $evalf_func_implementation $conjugate_func_implementation +$real_part_func_implementation +$imag_part_func_implementation $derivative_func_implementation $power_func_implementation $series_func_implementation @@ -640,6 +705,19 @@ function_options& function_options::conjugate_func(conjugate_funcp_exvector c) conjugate_f = conjugate_funcp(c); return *this; } +function_options& function_options::real_part_func(real_part_funcp_exvector c) +{ + real_part_use_exvector_args = true; + real_part_f = real_part_funcp(c); + return *this; +} +function_options& function_options::imag_part_func(imag_part_funcp_exvector c) +{ + imag_part_use_exvector_args = true; + imag_part_f = imag_part_funcp(c); + return *this; +} + function_options& function_options::derivative_func(derivative_funcp_exvector d) { derivative_use_exvector_args = true; @@ -1049,6 +1127,46 @@ ${conjugate_switch_statement} throw(std::logic_error("function::conjugate(): invalid nparams")); } +/** Implementation of ex::real_part for functions. */ +ex function::real_part() const +{ + GINAC_ASSERT(serial(base).eval_indexed(*this); } +ex indexed::real_part() const +{ + if(op(0).info(info_flags::real)) + return *this; + return real_part_function(*this).hold(); +} + +ex indexed::imag_part() const +{ + if(op(0).info(info_flags::real)) + return 0; + return imag_part_function(*this).hold(); +} + ex indexed::thiscontainer(const exvector & v) const { return indexed(ex_to(symtree), v); diff --git a/ginac/indexed.h b/ginac/indexed.h index 4ad25cb9..bbe94005 100644 --- a/ginac/indexed.h +++ b/ginac/indexed.h @@ -147,6 +147,8 @@ public: unsigned precedence() const {return 55;} bool info(unsigned inf) const; ex eval(int level = 0) const; + ex real_part() const; + ex imag_part() const; exvector get_free_indices() const; protected: diff --git a/ginac/inifcns.cpp b/ginac/inifcns.cpp index a8f82d8e..c49fc702 100644 --- a/ginac/inifcns.cpp +++ b/ginac/inifcns.cpp @@ -66,12 +66,114 @@ static ex conjugate_conjugate(const ex & arg) return arg; } +static ex conjugate_real_part(const ex & arg) +{ + return arg.real_part(); +} + +static ex conjugate_imag_part(const ex & arg) +{ + return -arg.imag_part(); +} + REGISTER_FUNCTION(conjugate_function, eval_func(conjugate_eval). evalf_func(conjugate_evalf). print_func(conjugate_print_latex). conjugate_func(conjugate_conjugate). + real_part_func(conjugate_real_part). + imag_part_func(conjugate_imag_part). set_name("conjugate","conjugate")); +////////// +// real part +////////// + +static ex real_part_evalf(const ex & arg) +{ + if (is_exactly_a(arg)) { + return ex_to(arg).real(); + } + return real_part_function(arg).hold(); +} + +static ex real_part_eval(const ex & arg) +{ + return arg.real_part(); +} + +static void real_part_print_latex(const ex & arg, const print_context & c) +{ + c.s << "\\Re"; arg.print(c); c.s << ""; +} + +static ex real_part_conjugate(const ex & arg) +{ + return real_part_function(arg).hold(); +} + +static ex real_part_real_part(const ex & arg) +{ + return real_part_function(arg).hold(); +} + +static ex real_part_imag_part(const ex & arg) +{ + return 0; +} + +REGISTER_FUNCTION(real_part_function, eval_func(real_part_eval). + evalf_func(real_part_evalf). + print_func(real_part_print_latex). + conjugate_func(real_part_conjugate). + real_part_func(real_part_real_part). + imag_part_func(real_part_imag_part). + set_name("real_part","real_part")); + +////////// +// imag part +////////// + +static ex imag_part_evalf(const ex & arg) +{ + if (is_exactly_a(arg)) { + return ex_to(arg).imag(); + } + return imag_part_function(arg).hold(); +} + +static ex imag_part_eval(const ex & arg) +{ + return arg.imag_part(); +} + +static void imag_part_print_latex(const ex & arg, const print_context & c) +{ + c.s << "\\Im"; arg.print(c); c.s << ""; +} + +static ex imag_part_conjugate(const ex & arg) +{ + return imag_part_function(arg).hold(); +} + +static ex imag_part_real_part(const ex & arg) +{ + return imag_part_function(arg).hold(); +} + +static ex imag_part_imag_part(const ex & arg) +{ + return 0; +} + +REGISTER_FUNCTION(imag_part_function, eval_func(imag_part_eval). + evalf_func(imag_part_evalf). + print_func(imag_part_print_latex). + conjugate_func(imag_part_conjugate). + real_part_func(imag_part_real_part). + imag_part_func(imag_part_imag_part). + set_name("imag_part","imag_part")); + ////////// // absolute value ////////// @@ -107,6 +209,16 @@ static ex abs_conjugate(const ex & arg) return abs(arg); } +static ex abs_real_part(const ex & arg) +{ + return abs(arg).hold(); +} + +static ex abs_imag_part(const ex& arg) +{ + return 0; +} + static ex abs_power(const ex & arg, const ex & exp) { if (arg.is_equal(arg.conjugate()) && is_a(exp) && ex_to(exp).is_even()) @@ -121,6 +233,8 @@ REGISTER_FUNCTION(abs, eval_func(abs_eval). print_func(abs_print_csrc_float). print_func(abs_print_csrc_float). conjugate_func(abs_conjugate). + real_part_func(abs_real_part). + imag_part_func(abs_imag_part). power_func(abs_power)); ////////// @@ -182,13 +296,25 @@ static ex step_series(const ex & arg, static ex step_conjugate(const ex& arg) { - return step(arg); + return step(arg).hold(); +} + +static ex step_real_part(const ex& arg) +{ + return step(arg).hold(); +} + +static ex step_imag_part(const ex& arg) +{ + return 0; } REGISTER_FUNCTION(step, eval_func(step_eval). evalf_func(step_evalf). series_func(step_series). - conjugate_func(step_conjugate)); + conjugate_func(step_conjugate). + real_part_func(step_real_part). + imag_part_func(step_imag_part)); ////////// // Complex sign @@ -249,7 +375,17 @@ static ex csgn_series(const ex & arg, static ex csgn_conjugate(const ex& arg) { - return csgn(arg); + return csgn(arg).hold(); +} + +static ex csgn_real_part(const ex& arg) +{ + return csgn(arg).hold(); +} + +static ex csgn_imag_part(const ex& arg) +{ + return 0; } static ex csgn_power(const ex & arg, const ex & exp) @@ -268,6 +404,8 @@ REGISTER_FUNCTION(csgn, eval_func(csgn_eval). evalf_func(csgn_evalf). series_func(csgn_series). conjugate_func(csgn_conjugate). + real_part_func(csgn_real_part). + imag_part_func(csgn_imag_part). power_func(csgn_power)); @@ -345,7 +483,17 @@ static ex eta_series(const ex & x, const ex & y, static ex eta_conjugate(const ex & x, const ex & y) { - return -eta(x,y); + return -eta(x, y); +} + +static ex eta_real_part(const ex & x, const ex & y) +{ + return 0; +} + +static ex eta_imag_part(const ex & x, const ex & y) +{ + return -I*eta(x, y).hold(); } REGISTER_FUNCTION(eta, eval_func(eta_eval). @@ -353,7 +501,9 @@ REGISTER_FUNCTION(eta, eval_func(eta_eval). series_func(eta_series). latex_name("\\eta"). set_symmetry(sy_symm(0, 1)). - conjugate_func(eta_conjugate)); + conjugate_func(eta_conjugate). + real_part_func(eta_real_part). + imag_part_func(eta_imag_part)); ////////// @@ -568,14 +718,26 @@ static void factorial_print_dflt_latex(const ex & x, const print_context & c) static ex factorial_conjugate(const ex & x) { - return factorial(x); + return factorial(x).hold(); +} + +static ex factorial_real_part(const ex & x) +{ + return factorial(x).hold(); +} + +static ex factorial_imag_part(const ex & x) +{ + return 0; } REGISTER_FUNCTION(factorial, eval_func(factorial_eval). evalf_func(factorial_evalf). print_func(factorial_print_dflt_latex). print_func(factorial_print_dflt_latex). - conjugate_func(factorial_conjugate)); + conjugate_func(factorial_conjugate). + real_part_func(factorial_real_part). + imag_part_func(factorial_imag_part)); ////////// // binomial @@ -620,12 +782,24 @@ static ex binomial_eval(const ex & x, const ex &y) // function, also complex conjugation should be changed (or rather, deleted). static ex binomial_conjugate(const ex & x, const ex & y) { - return binomial(x,y); + return binomial(x,y).hold(); +} + +static ex binomial_real_part(const ex & x, const ex & y) +{ + return binomial(x,y).hold(); +} + +static ex binomial_imag_part(const ex & x, const ex & y) +{ + return 0; } REGISTER_FUNCTION(binomial, eval_func(binomial_eval). evalf_func(binomial_evalf). - conjugate_func(binomial_conjugate)); + conjugate_func(binomial_conjugate). + real_part_func(binomial_real_part). + imag_part_func(binomial_imag_part)); ////////// // Order term function (for truncated power series) @@ -660,7 +834,19 @@ static ex Order_series(const ex & x, const relational & r, int order, unsigned o static ex Order_conjugate(const ex & x) { - return Order(x); + return Order(x).hold(); +} + +static ex Order_real_part(const ex & x) +{ + return Order(x).hold(); +} + +static ex Order_imag_part(const ex & x) +{ + if(x.info(info_flags::real)) + return 0; + return Order(x).hold(); } // Differentiation is handled in function::derivative because of its special requirements @@ -668,7 +854,9 @@ static ex Order_conjugate(const ex & x) REGISTER_FUNCTION(Order, eval_func(Order_eval). series_func(Order_series). latex_name("\\mathcal{O}"). - conjugate_func(Order_conjugate)); + conjugate_func(Order_conjugate). + real_part_func(Order_real_part). + imag_part_func(Order_imag_part)); ////////// // Solve linear system diff --git a/ginac/inifcns.h b/ginac/inifcns.h index 0e13a040..af5516db 100644 --- a/ginac/inifcns.h +++ b/ginac/inifcns.h @@ -31,13 +31,19 @@ namespace GiNaC { /** Complex conjugate. */ DECLARE_FUNCTION_1P(conjugate_function) + +/** Real part. */ +DECLARE_FUNCTION_1P(real_part_function) + +/** Imaginary part. */ +DECLARE_FUNCTION_1P(imag_part_function) /** Absolute value. */ DECLARE_FUNCTION_1P(abs) /** Step function. */ DECLARE_FUNCTION_1P(step) - + /** Complex sign. */ DECLARE_FUNCTION_1P(csgn) diff --git a/ginac/inifcns_trans.cpp b/ginac/inifcns_trans.cpp index 364ec55e..3f9c380b 100644 --- a/ginac/inifcns_trans.cpp +++ b/ginac/inifcns_trans.cpp @@ -89,9 +89,21 @@ static ex exp_deriv(const ex & x, unsigned deriv_param) return exp(x); } +static ex exp_real_part(const ex & x) +{ + return exp(GiNaC::real_part(x))*cos(GiNaC::imag_part(x)); +} + +static ex exp_imag_part(const ex & x) +{ + return exp(GiNaC::real_part(x))*sin(GiNaC::imag_part(x)); +} + REGISTER_FUNCTION(exp, eval_func(exp_eval). evalf_func(exp_evalf). derivative_func(exp_deriv). + real_part_func(exp_real_part). + imag_part_func(exp_imag_part). latex_name("\\exp")); ////////// @@ -232,10 +244,22 @@ static ex log_series(const ex &arg, throw do_taylor(); // caught by function::series() } +static ex log_real_part(const ex & x) +{ + return log(abs(x)); +} + +static ex log_imag_part(const ex & x) +{ + return atan2(GiNaC::imag_part(x), GiNaC::real_part(x)); +} + REGISTER_FUNCTION(log, eval_func(log_eval). evalf_func(log_evalf). derivative_func(log_deriv). series_func(log_series). + real_part_func(log_real_part). + imag_part_func(log_imag_part). latex_name("\\ln")); ////////// @@ -321,9 +345,21 @@ static ex sin_deriv(const ex & x, unsigned deriv_param) return cos(x); } +static ex sin_real_part(const ex & x) +{ + return cosh(GiNaC::imag_part(x))*sin(GiNaC::real_part(x)); +} + +static ex sin_imag_part(const ex & x) +{ + return sinh(GiNaC::imag_part(x))*cos(GiNaC::real_part(x)); +} + REGISTER_FUNCTION(sin, eval_func(sin_eval). evalf_func(sin_evalf). derivative_func(sin_deriv). + real_part_func(sin_real_part). + imag_part_func(sin_imag_part). latex_name("\\sin")); ////////// @@ -409,9 +445,21 @@ static ex cos_deriv(const ex & x, unsigned deriv_param) return -sin(x); } +static ex cos_real_part(const ex & x) +{ + return cosh(GiNaC::imag_part(x))*cos(GiNaC::real_part(x)); +} + +static ex cos_imag_part(const ex & x) +{ + return -sinh(GiNaC::imag_part(x))*sin(GiNaC::real_part(x)); +} + REGISTER_FUNCTION(cos, eval_func(cos_eval). evalf_func(cos_evalf). derivative_func(cos_deriv). + real_part_func(cos_real_part). + imag_part_func(cos_imag_part). latex_name("\\cos")); ////////// @@ -494,6 +542,20 @@ static ex tan_deriv(const ex & x, unsigned deriv_param) return (_ex1+power(tan(x),_ex2)); } +static ex tan_real_part(const ex & x) +{ + ex a = GiNaC::real_part(x); + ex b = GiNaC::imag_part(x); + return tan(a)/(1+power(tan(a),2)*power(tan(b),2)); +} + +static ex tan_imag_part(const ex & x) +{ + ex a = GiNaC::real_part(x); + ex b = GiNaC::imag_part(x); + return tanh(b)/(1+power(tan(a),2)*power(tan(b),2)); +} + static ex tan_series(const ex &x, const relational &rel, int order, @@ -514,6 +576,8 @@ REGISTER_FUNCTION(tan, eval_func(tan_eval). evalf_func(tan_evalf). derivative_func(tan_deriv). series_func(tan_series). + real_part_func(tan_real_part). + imag_part_func(tan_imag_part). latex_name("\\tan")); ////////// @@ -896,9 +960,21 @@ static ex sinh_deriv(const ex & x, unsigned deriv_param) return cosh(x); } +static ex sinh_real_part(const ex & x) +{ + return sinh(GiNaC::real_part(x))*cos(GiNaC::imag_part(x)); +} + +static ex sinh_imag_part(const ex & x) +{ + return cosh(GiNaC::real_part(x))*sin(GiNaC::imag_part(x)); +} + REGISTER_FUNCTION(sinh, eval_func(sinh_eval). evalf_func(sinh_evalf). derivative_func(sinh_deriv). + real_part_func(sinh_real_part). + imag_part_func(sinh_imag_part). latex_name("\\sinh")); ////////// @@ -961,9 +1037,21 @@ static ex cosh_deriv(const ex & x, unsigned deriv_param) return sinh(x); } +static ex cosh_real_part(const ex & x) +{ + return cosh(GiNaC::real_part(x))*cos(GiNaC::imag_part(x)); +} + +static ex cosh_imag_part(const ex & x) +{ + return sinh(GiNaC::real_part(x))*sin(GiNaC::imag_part(x)); +} + REGISTER_FUNCTION(cosh, eval_func(cosh_eval). evalf_func(cosh_evalf). derivative_func(cosh_deriv). + real_part_func(cosh_real_part). + imag_part_func(cosh_imag_part). latex_name("\\cosh")); ////////// @@ -1042,10 +1130,26 @@ static ex tanh_series(const ex &x, return (sinh(x)/cosh(x)).series(rel, order, options); } +static ex tanh_real_part(const ex & x) +{ + ex a = GiNaC::real_part(x); + ex b = GiNaC::imag_part(x); + return tanh(a)/(1+power(tanh(a),2)*power(tan(b),2)); +} + +static ex tanh_imag_part(const ex & x) +{ + ex a = GiNaC::real_part(x); + ex b = GiNaC::imag_part(x); + return tan(b)/(1+power(tanh(a),2)*power(tan(b),2)); +} + REGISTER_FUNCTION(tanh, eval_func(tanh_eval). evalf_func(tanh_evalf). derivative_func(tanh_deriv). series_func(tanh_series). + real_part_func(tanh_real_part). + imag_part_func(tanh_imag_part). latex_name("\\tanh")); ////////// diff --git a/ginac/matrix.cpp b/ginac/matrix.cpp index f62e2d40..3f3b2e6f 100644 --- a/ginac/matrix.cpp +++ b/ginac/matrix.cpp @@ -262,6 +262,24 @@ ex matrix::conjugate() const return *this; } +ex matrix::real_part() const +{ + exvector v; + v.reserve(m.size()); + for (exvector::const_iterator i=m.begin(); i!=m.end(); ++i) + v.push_back(i->real_part()); + return matrix(row, col, v); +} + +ex matrix::imag_part() const +{ + exvector v; + v.reserve(m.size()); + for (exvector::const_iterator i=m.begin(); i!=m.end(); ++i) + v.push_back(i->imag_part()); + return matrix(row, col, v); +} + // protected int matrix::compare_same_type(const basic & other) const diff --git a/ginac/matrix.h b/ginac/matrix.h index a1ac7cbc..08c9fe88 100644 --- a/ginac/matrix.h +++ b/ginac/matrix.h @@ -121,6 +121,8 @@ public: ex scalar_mul_indexed(const ex & self, const numeric & other) const; bool contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const; ex conjugate() const; + ex real_part() const; + ex imag_part() const; protected: bool match_same_type(const basic & other) const; diff --git a/ginac/mul.cpp b/ginac/mul.cpp index dd929f7e..d2dd675c 100644 --- a/ginac/mul.cpp +++ b/ginac/mul.cpp @@ -461,6 +461,41 @@ ex mul::evalf(int level) const return mul(s, overall_coeff.evalf(level)); } +void mul::find_real_imag(ex & rp, ex & ip) const +{ + rp = overall_coeff.real_part(); + ip = overall_coeff.imag_part(); + for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) { + ex factor = recombine_pair_to_ex(*i); + ex new_rp = factor.real_part(); + ex new_ip = factor.imag_part(); + if(new_ip.is_zero()) { + rp *= new_rp; + ip *= new_rp; + } else { + ex temp = rp*new_rp - ip*new_ip; + ip = ip*new_rp + rp*new_ip; + rp = temp; + } + } + rp = rp.expand(); + ip = ip.expand(); +} + +ex mul::real_part() const +{ + ex rp, ip; + find_real_imag(rp, ip); + return rp; +} + +ex mul::imag_part() const +{ + ex rp, ip; + find_real_imag(rp, ip); + return ip; +} + ex mul::evalm() const { // numeric*matrix diff --git a/ginac/mul.h b/ginac/mul.h index 7730bad0..d9023c2f 100644 --- a/ginac/mul.h +++ b/ginac/mul.h @@ -55,6 +55,8 @@ public: bool has(const ex & other, unsigned options = 0) const; ex eval(int level=0) const; ex evalf(int level=0) const; + ex real_part() const; + ex imag_part() const; ex evalm() const; ex series(const relational & s, int order, unsigned options = 0) const; ex normal(exmap & repl, exmap & rev_lookup, int level = 0) const; @@ -79,6 +81,7 @@ protected: void combine_overall_coeff(const ex & c1, const ex & c2); bool can_make_flat(const expair & p) const; ex expand(unsigned options=0) const; + void find_real_imag(ex&, ex&) const; // new virtual functions which can be overridden by derived classes // none diff --git a/ginac/ncmul.cpp b/ginac/ncmul.cpp index 81d0653e..21f7730c 100644 --- a/ginac/ncmul.cpp +++ b/ginac/ncmul.cpp @@ -508,6 +508,16 @@ ex ncmul::conjugate() const return (new ncmul(ev, true))->setflag(status_flags::dynallocated).eval(); } +ex ncmul::real_part() const +{ + return basic::real_part(); +} + +ex ncmul::imag_part() const +{ + return basic::imag_part(); +} + // protected /** Implementation of ex::diff() for a non-commutative product. It applies diff --git a/ginac/ncmul.h b/ginac/ncmul.h index cc156d54..d6fb40d1 100644 --- a/ginac/ncmul.h +++ b/ginac/ncmul.h @@ -65,6 +65,8 @@ public: ex thiscontainer(const exvector & v) const; ex thiscontainer(std::auto_ptr vp) const; ex conjugate() const; + ex real_part() const; + ex imag_part() const; protected: ex derivative(const symbol & s) const; diff --git a/ginac/numeric.cpp b/ginac/numeric.cpp index 278741f1..cc72565a 100644 --- a/ginac/numeric.cpp +++ b/ginac/numeric.cpp @@ -687,6 +687,16 @@ ex numeric::conjugate() const return numeric(cln::conjugate(this->value)); } +ex numeric::real_part() const +{ + return numeric(cln::realpart(value)); +} + +ex numeric::imag_part() const +{ + return numeric(cln::imagpart(value)); +} + // protected int numeric::compare_same_type(const basic &other) const diff --git a/ginac/numeric.h b/ginac/numeric.h index ff460638..09603f66 100644 --- a/ginac/numeric.h +++ b/ginac/numeric.h @@ -120,6 +120,8 @@ public: ex smod(const numeric &xi) const; numeric max_coefficient() const; ex conjugate() const; + ex real_part() const; + ex imag_part() const; protected: /** Implementation of ex::diff for a numeric always returns 0. * @see ex::diff */ diff --git a/ginac/power.cpp b/ginac/power.cpp index 0ebc8dc2..75fd2ff5 100644 --- a/ginac/power.cpp +++ b/ginac/power.cpp @@ -40,6 +40,7 @@ #include "lst.h" #include "archive.h" #include "utils.h" +#include "relational.h" namespace GiNaC { @@ -614,6 +615,59 @@ ex power::conjugate() const return (new power(newbasis, newexponent))->setflag(status_flags::dynallocated); } +ex power::real_part() const +{ + if (exponent.info(info_flags::integer)) { + ex basis_real = basis.real_part(); + if (basis_real == basis) + return *this; + realsymbol a("a"),b("b"); + ex result; + if (exponent.info(info_flags::posint)) + result = power(a+I*b,exponent); + else + result = power(a/(a*a+b*b)-I*b/(a*a+b*b),-exponent); + result = result.expand(); + result = result.real_part(); + result = result.subs(lst( a==basis_real, b==basis.imag_part() )); + return result; + } + + ex a = basis.real_part(); + ex b = basis.imag_part(); + ex c = exponent.real_part(); + ex d = exponent.imag_part(); + return power(abs(basis),c)*exp(-d*atan2(b,a))*cos(c*atan2(b,a)+d*log(abs(basis))); +} + +ex power::imag_part() const +{ + if (exponent.info(info_flags::integer)) { + ex basis_real = basis.real_part(); + if (basis_real == basis) + return 0; + realsymbol a("a"),b("b"); + ex result; + if (exponent.info(info_flags::posint)) + result = power(a+I*b,exponent); + else + result = power(a/(a*a+b*b)-I*b/(a*a+b*b),-exponent); + result = result.expand(); + result = result.imag_part(); + result = result.subs(lst( a==basis_real, b==basis.imag_part() )); + return result; + } + + ex a=basis.real_part(); + ex b=basis.imag_part(); + ex c=exponent.real_part(); + ex d=exponent.imag_part(); + return + power(abs(basis),c)*exp(-d*atan2(b,a))*sin(c*atan2(b,a)+d*log(abs(basis))); +} + +// protected + // protected /** Implementation of ex::diff() for a power. diff --git a/ginac/power.h b/ginac/power.h index c7645247..ad2b4af9 100644 --- a/ginac/power.h +++ b/ginac/power.h @@ -68,6 +68,8 @@ public: ex to_rational(exmap & repl) const; ex to_polynomial(exmap & repl) const; ex conjugate() const; + ex real_part() const; + ex imag_part() const; protected: ex derivative(const symbol & s) const; ex eval_ncmul(const exvector & v) const; diff --git a/ginac/pseries.cpp b/ginac/pseries.cpp index 41ec9036..14488ba7 100644 --- a/ginac/pseries.cpp +++ b/ginac/pseries.cpp @@ -412,21 +412,53 @@ ex pseries::evalf(int level) const ex pseries::conjugate() const { + if(!var.info(info_flags::real)) + return conjugate_function(*this).hold(); + epvector * newseq = conjugateepvector(seq); - ex newvar = var.conjugate(); ex newpoint = point.conjugate(); - if (!newseq && are_ex_trivially_equal(newvar, var) && are_ex_trivially_equal(point, newpoint)) { + if (!newseq && are_ex_trivially_equal(point, newpoint)) { return *this; } - ex result = (new pseries(newvar==newpoint, newseq ? *newseq : seq))->setflag(status_flags::dynallocated); + ex result = (new pseries(var==newpoint, newseq ? *newseq : seq))->setflag(status_flags::dynallocated); if (newseq) { delete newseq; } return result; } +ex pseries::real_part() const +{ + if(!var.info(info_flags::real)) + return real_part_function(*this).hold(); + ex newpoint = point.real_part(); + if(newpoint != point) + return real_part_function(*this).hold(); + + epvector v; + v.reserve(seq.size()); + for(epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) + v.push_back(expair((i->rest).real_part(), i->coeff)); + return (new pseries(var==point, v))->setflag(status_flags::dynallocated); +} + +ex pseries::imag_part() const +{ + if(!var.info(info_flags::real)) + return imag_part_function(*this).hold(); + ex newpoint = point.real_part(); + if(newpoint != point) + return imag_part_function(*this).hold(); + + epvector v; + v.reserve(seq.size()); + for(epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) + v.push_back(expair((i->rest).imag_part(), i->coeff)); + return (new pseries(var==point, v))->setflag(status_flags::dynallocated); +} + ex pseries::eval_integ() const { epvector *newseq = NULL; diff --git a/ginac/pseries.h b/ginac/pseries.h index fe88508c..0d1813aa 100644 --- a/ginac/pseries.h +++ b/ginac/pseries.h @@ -56,6 +56,8 @@ public: ex normal(exmap & repl, exmap & rev_lookup, int level = 0) const; ex expand(unsigned options = 0) const; ex conjugate() const; + ex real_part() const; + ex imag_part() const; ex eval_integ() const; protected: ex derivative(const symbol & s) const; diff --git a/ginac/symbol.cpp b/ginac/symbol.cpp index 10b38a8e..59dda652 100644 --- a/ginac/symbol.cpp +++ b/ginac/symbol.cpp @@ -220,12 +220,26 @@ ex symbol::eval(int level) const ex symbol::conjugate() const { if (this->domain == domain::complex) { - return GiNaC::conjugate_function(*this).hold(); + return conjugate_function(*this).hold(); } else { return *this; } } +ex symbol::real_part() const +{ + if (domain == domain::real) + return *this; + return real_part_function(*this).hold(); +} + +ex symbol::imag_part() const +{ + if (domain == domain::real) + return 0; + return imag_part_function(*this).hold(); +} + bool symbol::is_polynomial(const ex & var) const { return true; diff --git a/ginac/symbol.h b/ginac/symbol.h index b7c17a80..9c7e526d 100644 --- a/ginac/symbol.h +++ b/ginac/symbol.h @@ -75,6 +75,8 @@ public: unsigned return_type() const { return ret_type; } tinfo_t return_type_tinfo() const { return ret_type_tinfo; } ex conjugate() const; + ex real_part() const; + ex imag_part() const; bool is_polynomial(const ex & var) const; protected: ex derivative(const symbol & s) const; diff --git a/ginac/tensor.cpp b/ginac/tensor.cpp index 5b43e65a..c215237d 100644 --- a/ginac/tensor.cpp +++ b/ginac/tensor.cpp @@ -141,6 +141,22 @@ DEFAULT_COMPARE(tensdelta) DEFAULT_COMPARE(tensmetric) DEFAULT_COMPARE(spinmetric) +bool tensdelta::info(unsigned inf) const +{ + if(inf == info_flags::real) + return true; + + return false; +} + +bool tensmetric::info(unsigned inf) const +{ + if(inf == info_flags::real) + return true; + + return false; +} + int minkmetric::compare_same_type(const basic & other) const { GINAC_ASSERT(is_a(other)); @@ -152,6 +168,14 @@ int minkmetric::compare_same_type(const basic & other) const return inherited::compare_same_type(other); } +bool minkmetric::info(unsigned inf) const +{ + if(inf == info_flags::real) + return true; + + return false; +} + int tensepsilon::compare_same_type(const basic & other) const { GINAC_ASSERT(is_a(other)); @@ -165,6 +189,22 @@ int tensepsilon::compare_same_type(const basic & other) const return inherited::compare_same_type(other); } +bool tensepsilon::info(unsigned inf) const +{ + if(inf == info_flags::real) + return true; + + return false; +} + +bool spinmetric::info(unsigned inf) const +{ + if(inf == info_flags::real) + return true; + + return false; +} + DEFAULT_PRINT_LATEX(tensdelta, "delta", "\\delta") DEFAULT_PRINT(tensmetric, "g") DEFAULT_PRINT_LATEX(minkmetric, "eta", "\\eta") diff --git a/ginac/tensor.h b/ginac/tensor.h index b424cedf..d33603ae 100644 --- a/ginac/tensor.h +++ b/ginac/tensor.h @@ -60,6 +60,7 @@ class tensdelta : public tensor // functions overriding virtual functions from base classes public: + bool info(unsigned inf) const; ex eval_indexed(const basic & i) const; bool contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const; @@ -80,6 +81,7 @@ class tensmetric : public tensor // functions overriding virtual functions from base classes public: + bool info(unsigned inf) const; ex eval_indexed(const basic & i) const; bool contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const; @@ -104,6 +106,7 @@ public: // functions overriding virtual functions from base classes public: + bool info(unsigned inf) const; ex eval_indexed(const basic & i) const; // non-virtual functions in this class @@ -128,6 +131,7 @@ class spinmetric : public tensmetric // functions overriding virtual functions from base classes public: + bool info(unsigned inf) const; ex eval_indexed(const basic & i) const; bool contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const; @@ -151,6 +155,7 @@ public: // functions overriding virtual functions from base classes public: + bool info(unsigned inf) const; ex eval_indexed(const basic & i) const; bool contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const;