pax_global_header00006660000000000000000000000064126417636470014532gustar00rootroot0000000000000052 comment=378fd8db8ad9f9bf5f36d0d992f8f750bd845dd3 pynac-pynac-0.6.0/000077500000000000000000000000001264176364700137575ustar00rootroot00000000000000pynac-pynac-0.6.0/.hgignore000066400000000000000000000002431264176364700155610ustar00rootroot00000000000000%*.la %*.lo %*.o %*~ %*.libs/ %*.rej .*sw[p-z]$ ginac/tags Makefile config.guess config.sub stamp-h1 version.h pynac.pc pynac.spec m4 install-sh ltmain.sh missing pynac-pynac-0.6.0/AUTHORS000066400000000000000000000017671264176364700150420ustar00rootroot00000000000000The Pynac Group --------------- William Stein Burcin Erocal The GiNaC Group --------------- Christian Bauer Chris Dams Alexander Frink Vladimir V. Kisil Richard Kreckel Alexei Sheplyakov Jens Vollinga Contributors of patches ----------------------- Roberto Bagnara, Do Hoang Son, Markus Nullmeier, Pearu Peterson, Benedikt Pluemper, Ben Sapp, Stefan Weinzierl. (Please send email if you think you were forgotten.) Contacing the authors --------------------- If you have found a bug, have a patch or a question or would like to make a suggestion please send email to one of our public mailing lists instead of to one or more of the authors. This avoids both potential duplication of work and delays caused by possible vacations. Mailing list subscription is explained at . pynac-pynac-0.6.0/COPYING000066400000000000000000000433631264176364700150230ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. pynac-pynac-0.6.0/ChangeLog000066400000000000000000000005601264176364700155320ustar00rootroot00000000000000This file is not yet operational. Eventually it should record all changes. Till then, you are advised to resort to our CVS server where all changes are logged. This is how to get anonymous read-only access: $ cvs -d :pserver:anoncvs@cvs.ginac.de:/home/cvs/GiNaC login enter the password `anoncvs' $ cvs -d :pserver:anoncvs@cvs.ginac.de:/home/cvs/GiNaC -z 9 co GiNaC pynac-pynac-0.6.0/INSTALL000066400000000000000000000122311264176364700150070ustar00rootroot00000000000000PREREQUISITES ============= GiNaC requires the CLN library by Bruno Haible installed on your system. It is available from . You will also need a decent ANSI-compliant C++-compiler. We recommend the C++ compiler from the GNU compiler collection, GCC >= 3.4. If you have a different or older compiler you are on your own. Note that you may have to use the same compiler you compiled CLN with because of differing name-mangling schemes. The pkg-config utility is required for configuration, it can be downloaded from . To build the GiNaC tutorial and reference manual the doxygen utility (it can be downloaded from http://www.stack.nl/~dimitri/doxygen) and TeX are necessary. Known to work with: - Linux on x86 and x86_64 using GCC 3.4, 4.0, 4.1, and 4.2. - Linux on Alpha using GCC 3.4. - Solaris on Sparc using GCC 3.4. - Windows on x86 using GCC 3.4 (MinGW) Known not to work with: - GCC 4.3.0 due to the compiler bug, see . - GCC 2.96 or earlier because proper exception and standard library support is missing there. If you install from CVS, you also need GNU autoconf (>=2.59), automake (>=1.7), libtool (>= 1.5), bison (>= 2.3), flex (>= 2.5.33) to be installed. INSTALLATION ============ To install from a source .tar.bz2 distribution: $ ./configure $ make [become root if necessary] # make install To build the GiNaC tutorial and reference manual in HTML, DVI, PostScript, or PDF formats, use one of $ make html $ make dvi $ make ps $ make pdf To compile and run GiNaC's test and benchmark suite and check whether the library works correctly you can use $ make check The "configure" script can be given a number of options to enable and disable various features. For a complete list, type: $ ./configure --help A few of the more important ones: --prefix=PREFIX install architecture-independent files in PREFIX [defaults to /usr/local] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [defaults to the value given to --prefix] --disable-shared suppress the creation of a shared version of libginac --disable-static suppress the creation of a static version of libginac More detailed installation instructions can be found in the documentation, in the doc/ directory. The time the "make" step takes depends heavily on optimization levels. Large amounts of memory (>128MB) will be required by the compiler, also depending on optimization. To give you a rough idea of what you have to expect the following table may be helpful. It was measured on an Athlon/800MHz with "enough" memory: step | GCC optimization | comment | -O1 | -O2 | --------------+---------+---------+---------------------------------------- make | ~6m | ~8m | shared and static library make check | ~8m | ~12m | largely due to compilation To install from CVS =================== First, download the code: $ cvs -d :pserver:anoncvs@cvs.ginac.de:/home/cvs/GiNaC login [enter "anoncvs" as the password] $ cvs -d :pserver:anoncvs@cvs.ginac.de:/home/cvs/GiNaC co GiNaC $ cd GiNaC Secondly, make sure all required software is installed. This is *really* important step. If some package is missing, the `configure' script might be misgenerated, see e.g. this discussion: Finally, run $ autoreconf -i to generate the `configure' script, and proceed in a standard way, i.e. $ ./configure $ make [become root if necessary] # make install COMMON PROBLEMS =============== Problems with CLN ----------------- You should use at least CLN-1.1, since during the development of GiNaC various bugs have been discovered and fixed in earlier versions. Please install CLN properly on your system before continuing with GiNaC. Problems building ginsh ----------------------- The GiNaC interactive shell, ginsh, makes use of GNU readline to provide command line editing and history. If readline library and/or headers are missing on your system, the configure script will issue a warning. In this case you have two options: 1) (the easiest) If you don't intend to use ginsh (i.e. if you need GiNaC library to compile some piece of software), ignore it. ginsh builds just fine without readline (obviously, it won't support the command line history and editing). 2) Install GNU readline and run the configure script once again. Depending on what your system/distribution is, you will have to install a package called libreadline and libreadline-dev (or readline-devel). If your system's vendor doesn't supply such packages, go to and compile it yourself. Note that non-GNU versions of libreadline (in particular one shipped with Mac OS X) are not supported at the moment. Problems with missing standard header files ------------------------------------------- Building GiNaC requires many standard header files. If you get a configure error complaining about such missing files your compiler and library are probably not up to date enough and it's no worth continuing. pynac-pynac-0.6.0/Makefile.am000066400000000000000000000010121264176364700160050ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in SUBDIRS = ginac DIST_SUBDIRS = ginac # pkg-config metadata pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = pynac.pc $(pkgconfig_DATA): config.status # All the rest of the distributed files EXTRA_DIST = pynac.pc pynac.spec # Rule to build tar-bzipped distribution package $(PACKAGE)-$(VERSION).tar.gz: dist # Rule to build RPM distribution package rpm: $(PACKAGE)-$(VERSION).tar.gz rpmbuild -ta --clean $(PACKAGE)-$(VERSION).tar.gz ACLOCAL_AMFLAGS=-I m4 pynac-pynac-0.6.0/NEWS000066400000000000000000000772521264176364700144730ustar00rootroot00000000000000This file records noteworthy changes. 1.4.3 (04 April 2008) * Fixed bug in numerical evaluation of multiple polylogarithms and alternating multiple zeta values introduced in version 1.4.2. * Nielsen polylog now invalidates its lookup tables in case the precision (Digits) has been changed. * Added new checks for recent bugs in the numerical evaluation of Li and zeta. 1.4.2 (03 April 2008) * Fixed VPATH building of documentation. * Fixed bug in numerical evaluation of multiple polylogarithms for arguments equal to certain roots of unity (thanks to Jianqiang Zhao). * Fixed check for memory leakage in parser. * Made internal function coerce() standard compliant. * Improved lsolve() of systems containing non-numeric coefficients. * Improved automatic test programs. Now they work on MinGW and Cygwin as well. 1.4.1 (21 November 2007) * Fixed memory leak in ginac_yylex(). * Fixed memory leaks in mul::eval() and power::eval(). * Fixed macro checking for version of libreadline (Mac OS X). * Fixed broken preprocessor instruction in excompiler.cpp. * Fixed broken module loading in excompiler.cpp. * info(info_flags::has_indices) now works for sums and products. * Improved mul::expand(). * Improved CLN output. 1.4.0 (31 August 2007) * New tinfo mechanism. * Removed rtt from class symbol. * Faster archiving by adding a map from strings to indices in the atoms vector. * Improved unarchiving: algorithms order N instead of order N^2. * Added compile function, excompiler class. * Added exset type. * Added step function to GiNaCs built-in functions. * Added is_polynomial() method. * Added real_part() and imag_part() methods. * Added matrix::is_zero_matrix() method. * Added evalm() method to pseries class. * Improved dummy index renaming. * Many improvements for class clifford. * New flag for positive symbols/numbers, added possymbol class. * Added programming examples in doc/examples 1.3.9 (21 November 2007) Backporting bug-fix release from version 1.4.1. 1.3.8 (28 August 2007) * Drop support of ginac-config and ginac.m4. Please use pkg-config instead. * atan2(y,x) branch cut correction. * Fixed bug in series expansion. * Additional transformations for mul and power. * Clifford units now honor representation labels. * Correct csrc output for idx and fderivative. * Improved handling of convergence transformationis for Li/G. * Fix compilation issues with prereleases of GCC 4.3. * info_flags::expanded added. * input_parser also accepts pow(). * texinfo.tex removed from package. 1.3.7 (05 February 2007) * Fixed bug in expansion of power. * Fixed bugs in functions S() (infinite loop), H() and zeta() (wrong results). * Rebuilt bison related files with bison version 2.3 (fixes parse error bugs). * Improved power::eval(). * Improved libreadline detection. 1.3.6 (13 December 2006) * Better worst case behavior in heuristic gcd. * Improved collecting for sparse multivariate polynomials. * Improved collect_common_factors. * Fixed bug in numerical evaluation of multiple polylogs. * Fixed numerical integration of complex functions. * Fixed bug in tensor::replace_contr_index(). 1.3.5 (17 August 2006) * Re-built bison related files that caused bugs with gcc 4. * Fixed bugs in fderivative::match_same_type(), expairseq::match(), expand_dummy_sum(), and expairseq::map(). * Fixed template specialization for class container to be gcc 4.2 compliant. * Output in csrc mode is now -x instead of -1.0*x. * Fixed tutorial and reference generation in html/pdf/ps format. * Modified autotool configuration to allow for compilation on MinGW. * Debian packaging files updated. 1.3.4 (12 April 2006) * More general index dimensions are now possible. * Improved algebraic substitutions. * Fixed wrong matching in .has(). * Fixed bug in differentiation of a power. * collect_common_factors also works with negative powers of common factors now. * Code clean-up and preparations for upcoming cln 1.2. 1.3.3 (24 October 2005) * Fixed bug occuring in algebraic substitutions with expressions involving indices. * Fixed bug that selected the wrong algorithm for determinants of purely numeric matrices with at least one floating point element. * Fixed bug in function H that caused an infinite recursion for arguments around +-I. * Fixed const-correctness in printing handler for GCC 4.0.2. * Made lookup in adaptivesimpson precision-aware. * Added series expansion for functions (classical) Li and S around x==0. * Added fsolve() numerical univariate real-valued function solver. * Added functions sub_matrix() and reduced_matrix(). * Small cleanups. Less warnings with latest GCC. 1.3.2 (10 July 2005) * GCD avoids to produce expanded expressions. * Fixed bug in expanding expressions containing dummy indices. * Fixed static initialization order bug. * collect_common_factors now works with powers. * Modernized configuration scripts. 1.3.1 (04 May 2005) * integral() and eval_integ() can be used from ginsh. * Integrals can be series-expanded. * Fixed a library initialization problem. * GiNaC compiles from tarball even if lex/flex is missing. * Fixed bugs in canonicalize_clifford(), clifford_prime() and clifford_to_lst(). * clifford_moebius_map(), remove_dirac_ONE() and LaTeX output of Clifford objects now care about representation labels. * Fixed bug in gcd. * Better output for slashed expressions 1.3.0 (19 October 2004) * The Clifford classes have been generalized to allow working with Clifford algebras generated by arbitrary symmetric tensors or matrices. Also, a lot of new functions for Clifford algebras have been added, including automorphisms and Moebius transformations. [V. Kisil] * Added some basic symbolic and numeric integration facilities. [C. Dams] * The multiple polylogarithm Li() now evaluates numerically for arbitrary arguments. * New functions G(a,y) and G(a,s,y) added (another notation for multiple polylogarithms). 1.2.4 (12 October 2004) * Added ex::unitcontprim() to compute the unit, content, and primitive parts of a polynomial in one go. * binomial(n, k) evaluates for non-integer arguments n. * Li(2,x) now evaluates for +-I. * Optimized Li(2,x). * Fixed bug in Li(n,x) (if Li(2,x) was calculated with high precision the enlargement of the look-up table caused a segmentation fault). * Fixed another bug in the series expansion of powers, and a bug in power::info(). 1.2.3 (13 August 2004) * Added variants of dirac_trace() and color_trace() that take the trace over more than one representation label by specifying a set or list of labels. * diracgamma::contract_with() uses Chisholm identities in 4 dimensions to produce more compact results. * Fixed a bug in the series expansion of powers. * The --enable-html-doc and --enable-ps-doc configure options are gone. Documentation in HTML, DVI, PostScript, and PDF formats is now built with "make html", "make dvi", "make ps", and "make pdf", respectively. The only documentation that gets built by default are the tutorial in .info format and the manpages. 1.2.2 (3 August 2004) * Added const_preorder_iterator and const_postorder_iterator classes (and associated methods ex::pre/postorder_begin/end()) providing tree traversal with iterators. * Fixed the LaTeX output of the varidx class. * Fixed bugs in series expansion and complex conjugation. * (p.i*p.i).get_free_indices() returns the correct result () instead of (.i). * Symbolic functions without any eval(), evalf() etc. functions now work properly. * integer_content(), content(), and primpart() now also work for polynomials with rational coefficients (calculating the LCM of coefficients' denominators). * Added method matrix::rank(). * Added function resultant(). * Added integer_content() function to ginsh. 1.2.1 (23 April 2004) * Fixed infinite recursion in atan2_evalf() and improved atan2_eval(). * Added automatic evaluations for trigonometric functions with negative arguments (e.g. sin(-2) -> -sin(2)). * Fixed a static initialization order goof-up. * Fixed various bugs in series expansion. 1.2.0 (19 March 2004) * Added a structure template class for the easy creation of user-defined algebraic classes. * Added support for (acyclic) visitors, to allow cleaner implementations of algebraic algorithms. * Added a const_iterator class that can be used instead of op()/nops(). * Completely revamped the implementation of expression output. It is now possible to add new output formats, to change the behavior of predefined formats at run-time, and to have different output styles for algebraic functions. * Symbols can be made non-commutative. * Added a method ex::conjugate() and a function conjugate() for complex conjugation. Symbols can be declared as real or complex-valued. * Improved the speed of subs(), normal(), to_rational() and to_polynomial() by the use of maps instead of lists. The old forms subs(const lst & ls, const lst & lr, unsigned options) to_rational/to_polynomial(lst & repl) are still available for compatibility, but using the new forms subs(const exmap & m, unsigned options) to_rational/to_polynomial(exmap & repl) is more efficient, especially when the number of replacements is large. * quo(), rem(), prem(), sprem(), decomp_rational(), unit(), content(), primpart() and matrix::charpoly() now take a "const ex &" instead of a "const symbol &". * Redundant expressions (two ex pointing to different objects are found to be equal in compare()) are now actively deleted/fused to conserve memory and speed up subsequent comparisons. This behavior can be suppressed on a per-object level with status_flags::not_shareable. Lists and matrices are not shareable by default. * Lots of internal streamlining and optimizations. * Caveats for class implementors: - basic::copy() and basic::destroy() are gone; classes derived from basic can use the defaults for the assignment operator and copy constructor. - basic::subs(), basic::normal(), basic::to_rational() and basic::to_polynomial() take 'exmap' objects instead of lists. - basic::subs() now descends into subexpressions (if accessible via nops()/op()/let_op()). If you have a custom implementation of subs() that calls basic::subs() after substituting subexpressions, this needs to be changed to a call to subs_one_level(). - lst::thislst() and exprseq::thisexprseq() renamed to thiscontainer(). - thiscontainer() and associated constructors now take a std::auto_ptr. - Overloading basic::print() is now deprecated. You should use print_func<>() class options instead. 1.1.7 (11 March 2004) * Fixed a bug in canonicalize_clifford(). * Series expansion now works predictably. All terms with the exponent of the expansion variable smaller than the given order are calculated exactly. If the series is not terminating, the Order function is (at least) of the given order. 1.1.6 (22 January 2004) * Added a function option "dummy()" which means "no options". This simplifies the implementation of symbolic functions which are not to be further evaluated. * Removed a bug in the numerical evaluation of Li() that caused the system to hang for certain parameter combinations. * Fixed a bug in the calculation of hash values for indices that could lead to wrong results or bogus error messages from simplify_indexed(). * Fixed a bug in the evaluation of harmonic polylogarithms for complex arguments with positive imaginary part. 1.1.5 (5 November 2003) * Harmonic polylogarithms now numerically evaluate for arbitrary arguments (parameter must still be positive integers). * The zeta function now can also be given a lst as a parameter in which case it becomes a multiple zeta value. The use of mZeta is deprecated. * The order of parameters for the multiple polylogarithm has been corrected. * Documentation for the nested sums functions zeta, harmonic polylog, multiple polylog, etc. has been added. 1.1.4 (17 October 2003) * Lists and matrices can now be initialized from comma-separated lists of expressions, like this: lst l; l = x, 2, y, x+y; matrix M(3, 3); M = x, y, 0, -y, x, 0, 0, 0, 1; This is both faster and produces much smaller code than the old constructors lst(ex, ex, ...) and matrix(unsigned, unsigned, lst), especially in the case of matrices, and is now the recommended way to create these objects. * The function mZeta now evaluates much faster for arbitrary parameters. The harmonic and multiple polylogarithms evaluate considerably faster and check for convergence. The order of parameters for the harmonic polylogarithm has been corrected. 1.1.3 (22 August 2003) * Added new symbolic functions for better integration with nestedsums: (multiple) polylogarithm Li(), Nielsen's generalized polylogarithm S(), harmonic polylogarithm H(), and multiple zeta value mZeta(). * New exhashmap template intended as a drop-in replacement for std::map using GiNaC's hashing algorithms. 1.1.2 (11 August 2003) * Fixed a bug in the unarchiving of sums and products: terms were not reordered in a canonical way. * Fixed a bug in normal()/numer_denom(): denominator was not made unit normal if it was a simple number. * Improved the speed of subs() in some cases. 1.1.1 (18 June 2003) * lst (and exprseq) provide iterators for read-only element access. For sequential access this is one order faster than using op(). * Implemented relational::subs() (this was done in 1.0.9 but inadvertently omitted from the 1.1 branch). * pole_error and do_taylor are available to library users. * Added on-line help and Tab-completion for print(), iprint(), print_latex() and print_csrc() in ginsh. 1.1.0 (3 April 2003) * Removed deprecated macros is_ex_a, is_ex_exactly_a and friends for good. * The scalar_products mechanism allows the specification of an index dimension. * Removed dirac_gamma6/7(). * Added ex::to_polynomial(). * subs() accepts an optional "options" argument. The option subs_option::subs_algebraic enables "smart" substitutions in products and powers. * Added stream manipulators "dflt", "latex", "python", "python_repr", "tree", "csrc", "csrc_float", "csrc_double", "csrc_cl_N", "index_dimensions" and "no_index_dimensions" to control the output format. Calling basic::print() directly is now deprecated. * Made the hashing more simple and efficient. * Caveats for class implementors: - basic::subs(): third argument changed from "bool" to "unsigned" - unarchiving constructor and basic::unarchive(): "const" removed from second argument - basic::let_op() should only be implemented if write access to subexpressions is desired - simplify_ncmul() renamed to eval_ncmul() - simplified_ncmul() renamed to hold_ncmul() - nonsimplified_ncmul() renamed to reeval_ncmul() 1.0.14 (1 March 2003) * Improved the C-source output: complex numbers are printed correctly (using the STL complex<> template or cln::complex()), rational numbers use cl_RA() in the CLN output, and small integers are printed in a more compact format (e.g. "2.0" instead of "2.0000000e+00"). * function_options::set_return_type() and function_options::do_not_evalf_params() now actually work. 1.0.13 (27 January 2003) * Contracting epsilon tensors with Euclidean indices now works. * Improved dummy index symmetrization in sums. * Added dirac_gammaL/R(), which can be used instead of dirac_gamma6/7() but are single objects, to allow for a more compact notation of Dirac strings. * Powers with negative numeric exponents are printed as fractions in the LaTeX output. * Added symbolic_matrix() for the convenient creation of matrices filled with symbols. * Added collect_common_factors() which collects common factors from the terms of sums. * simplify_indexed() converts "gamma~mu*p.mu" to "p\". 1.0.12 (30 October 2002) * Fixed a bug in power::expand() that could produce invalid expressions. * The input parser no longer ignores extra data following accepted input. * Improved the CLN C-source output (integers are printed as integers, and floating point numbers include the precision). * Fixed a problem in the LaTeX-output of negative fractions. * Added print_latex() and print_csrc() to ginsh. * The sprem() function is now public. 1.0.11 (18 September 2002) * Fixed a possible memory corruption in contractions of indexed objects with delta or metric tensors. * Computing the derivative of a power series object with respect to a symbol that is not the expansion variable now works correctly. * Several bugfixes in code generation. 1.0.10 (24 July 2002) * Powers of indexed objects are now parenthesized correctly in LaTeX output. * Input parser handles indices (they have to be specified in the same list as the symbols). * Added some limited support for subspaces in the idx and tensor classes. * Fixed a bug in canonicalize() (antisymmetric canonicalization of an already sorted list containing two or more equal objects failed to return 0). 1.0.9 (11 June 2002) * simplify_indexed() now raises/lowers dummy indices to canonicalize the index variance. This allows some simplifications that weren't possible before, like eps~a.b~c~d*X.a*X~b -> 0 and X.a~a-X~a.a -> 0. * Implemented relational::subs(). * Fixed bug in simplify_ncmul() for clifford objects. 1.0.8 (31 March 2002) * Improvements in memory usage of the expand() methods. 1.0.7 (18 March 2002) * Fixed LaTeX output of indexed and matrix objects. * Fixed matrix::pow(n) for n==0 and added helper functions to create unit matrices "ex unit_matrix(unsigned, unsigned)". 1.0.6 (4 March 2002) * "(x+1).subs(x==x-1)" now returns the correct result "x" instead of "x-1". 1.0.5 (27 January 2002) * (l)degree(s), coeff(s, n) and collect(s) were extended to accept expressions of any class (except add/mul/ncmul/numeric) for "s". They should even work if "s" is a "power" object, as long as the exponent is non-integer, but with some limitations. For example, you can "collect(a*2^x+b*2^x, 2^x)" to get "(a+b)*2^x", but "degree(2^(3*x), 2^x)" yields 0 instead of 3). * Fixed a small output bug. 1.0.4 (24 January 2002) * Speedup in expand(). * Faster Bernoulli numbers (Markus Nullmeier). * Some minor bugfixes and documentation updates. 1.0.3 (21 December 2001) * Fixed a bug where quo() would call vector::reserve() with a negative argument. * Fix several bugs in code generation. 1.0.2 (19 December 2001) * Input parser recognizes "sqrt()", which is also used in the output. * divide(a,b,q) only modifies q if the division succeeds; also, divide(a,b,a) works now. * Fixed small bug in dummy index renaming which could cause it to not recognize renamable indices in some cases. * power::degree() and power::ldegree() throw an exception when encountering a non-integer exponent. * Add output-support for Python bindings. 1.0.1 (22 November 2001) * Function sqrfree() handles a few more cases now. * Class relational has real canonical ordering now. * Handle obscene libreadline version numbers when building ginsh. 1.0.0 (6 November 2001) * Some internal reorganization resulting in a general speed-up. * The last 3 evaluated expressions in ginsh are now referred to with the tokens '%', '%%' and '%%%'. The old '"', '""' and '"""' remain for compatibility but may be removed in a future version of GiNaC. 0.9.4 (20 September 2001) * Functions have better support for external scripting languages. * Interface cleanups and bugfixes. * Fix silly bug in evalf() that prevented things like 2^Pi being computed. 0.9.3 (16 August 2001) * series expansion now much more consistent for small order expansion. * lsolve() accepts algorithmic hint as parameter. 0.9.2 (31 July 2001) * Epsilon tensor is more functional. * simplify_indexed() is better at detecting expressions that vanish for symmetry reasons. * Several little bugfixes and consistency enhancements. 0.9.1 (27 June 2001) * Ctors of class numeric are not explicit any more. All built-in callers for pseudofunctions are now templated and default to ex arguments which relaxes the need for explicit ctors. * New functions/methods: - find() - remove_first(), remove_last(), sort() and unique() for lists - symmetrize_cyclic() - decomp_rational() * Instead of just totally symmetric or antisymmetric, complex symmetries can now be defined for indexed objects. Symmetries are described by a tree of "symmetry" objects that is constructed with the sy_none(), sy_symm(), sy_anti() and sy_cycl() functions. The symmetry of a function with respect to its arguments can also be defined (this is currently only used for the Beta function). * Generalized map() to take a function object instead of a function pointer. This allows passing an arbitrary number of additional state to the function being called. * color_trace(), dirac_trace(), diff(), expand(), evalf() and normal() work better with container classes, e.g. using color_trace() on a relation will take the trace on both sides, using diff() on a matrix differentiates every element etc. * diff() works properly with non-commutative products and indexed objects. * New option flag "expand_function_args" for expand(). * Supplement some (now deprecated) macros by inlined template functions: - is_of_type(foo, type) -> is_a(foo) - is_ex_of_type(foo, type) -> is_a(foo) - is_exactly_of_type(foo, type) -> is_exactly_a(foo) - is_ex_exactly_of_type(foo, type) -> is_exactly_a(foo) - ex_to_foobar(baz) -> ex_to(baz) * rem(c, p[x], x) (c: numeric, p[x]: polynomial) erroneously returned p[x] instead of c. * Small bugfixes in pattern matching. * Updated libtool to version 1.4. 0.9.0 (7 June 2001) * In the output and in ginsh, lists are now delimited by { } braces, and matrices are delimited by single [ ] brackets. * simplify_indexed() renames dummy indices so, e.g., "a.i*a.i+a.j*a.j" gets simplified to "2*a.i*a.i" (or "2*a.j*a.j"). * New functions/methods: - canonicalize_clifford() (helpful when comparing expressions containing Dirac matrices) - symmetrize() and antisymmetrize() - numer_denom() (return numerator and denominator in one call) - map() (apply function to subexpressions) - evalm() (evaluate sums, products and integer powers of matrices) * Added a new function match() for performing pattern matching. subs() and has() also accept patterns as arguments. A pattern can be any expression, optionally containing wildcard objects. These are constructed with the call "wild()" and are denoted as "$0", "$1" etc. in the output and in ginsh. * Positive integer powers of non-commutative expressions (except matrices) are automatically expanded. * Removed cint subdirectory, ginaccint is a separate package now due to packaging considerations. * Several little bugfixes. 0.8.3 (11 May 2001) * color and clifford classes are functional and documented. * New "spinidx" class for dotted/undotted indices. * Predefined spinor metric tensor (created by spinor_metric()). * Symbols can have a LaTeX name, e.g. symbol s("s", "\\sigma"); * LaTeX output of indexed objects is much nicer. * Fixed some build problems (with recent libreadline). * Semantics of arithmetic operators now follows the C++ rules more strictly. 0.8.2 (24 April 2001) * degree(), ldegree(), coeff(), lcoeff(), tcoeff() and collect() work with non-symbols as the second argument in ginsh. * the argument to collect() can be a list of objects in which case the result is either a recursively collected polynomial, or a polynomial in a distributed form with terms like coeff*x1^e1*...*xn^en, as specified by the second argument to collect(). * Several bugfixes (including a nasty memory leak in .normal()). * class matrix: solve() doesn't call algorithms redundantly any more and inverse() falls back to solve() which works in more general cases. 0.8.1 (16 April 2001) * degree(), ldegree(), coeff(), lcoeff(), tcoeff() and collect() can now be used with constants, functions and indexed expressions as well, so you can use it to collect by powers of Pi or sin(x), or to find the coefficient of gamma~0. Limitations: - it only works with symbols, constants, functions and indexed expressions, trying to find the coefficient of, e.g., "x^2" or "x+y" won't work; - it does not know about dummy index summations; the coefficient of gamma~0 in p.mu*gamma~mu should be p.0 but is returned as 0; - using coeff(), tcoeff(), lcoeff() or collect() on elements of noncommutative products might return wrong or surprising results. * subs() no longer only substitutes symbols and indices but performs a more general "syntactic substitution", i.e. it substitutes whole objects in sub- expressions. You can subs((a+b)^2,a+b==3) and get 9, but subs(a+b+c,a+b==3) doesn't do anything. Limitations: - substituting numerics (subs(expr, 2==4)) will not replace then in all occurences; in general, you shouldn't substitute numerics, though. * Added preliminary (re)implementations of color and clifford classes. * simplify_indexed(): contraction of symmetric and antisymmetric tensors is zero. * Replaced the various print*() member functions by a single print() that takes a print_context object that determines the output formatting. This should make it easier to add more output types, such as LaTeX output, which is based on work by Stefan Weinzierl. * Added functions to retrieve the properties stored in archive objects outside of unarchive() (for printing or debugging purposes). * Some bugfixes (indexed objects, archive writing). * .collect() on non-polynomials is now algebraically correct. 0.8.0 (24 March 2001) * Complete revamp of indexed objects. Instead of multiple classes for indexed things and their indices there is now only one "indexed" class and two types of indices: "idx" for simple indices and "varidx" for indices with variance. There are predefined delta, epsilon and metric tensors, and a function simplify_indexed() that performs canonicalization and dummy index summations. Matrix objects can be indexed for doing simple linear algebra. * Added an option "expand_indexed" to expand() to perform expansion of indexed objects like (a+b).i -> a.i + b.i * Renamed get_indices() to get_free_indices(), which no longer returns dummy indices and checks the consistency of indices in sums. * sqrfree() factorization fixed and improved syntactically. * subs() works on matrices. * Matrices can be constructed from flat list of elements; diagonal matrices can be constructed from list of diagonal elements with diag_matrix(). * Fixed memory leak in expand(). * Operator% for objects of class ncmul has gone. Use operator* now for that case too, which is much more natural. 0.7.3 (28 February 2001) * Several bugfixes and minor performance tunings. * Added a section to the tutorial about adding new algebraic classes to GiNaC. * Closed many in-source documentation gaps. 0.7.2 (17 February 2001) * Several bugfixes in power series expansion, one of them critical. 0.7.1 (7 February 2001) * Fix problems with Cint that were caused by CLN's overloaded operator new. * Fix compilation errors with GCC3. * normal() handles large sums of fractions better and normalizes the exponent of power expressions. * expand() always expands the exponent and transforms x^(a+b) -> x^a*x^b. * Some bugfixes of series expansion around branch cuts of special functions. 0.7.0 (15 December 2000) * Requires CLN 1.1 now. Class numeric doesn't use an indirect pointer to the actual representation any more. This is a speedup. * mul::expand() was reengineered to not allocate excess temporary memory. * Non-integer powers of a symbol are treated as constants by (l)degree() and coeff(). Using these functions on an expression containing such powers used to fail with an internal error message. The side-effect is that collect() can be used on expressions which are not polynomials. * Added a man page for the ginac-config script. * Ctor of numeric from char* honors Digits. 0.6.4 (10 August 2000) * Complete revamp of methods in class matrix. Some redundant (and poor) implementations of elimination schemes were thrown out. The code is now highly orthogonal, more flexible and much more efficient. * Some long standing and quite nasty bugs were discovered and fixed in the following functions: add::normal(), heur_gcd(), sr_gcd() and Order_eval(). 0.6.3 (25 July 2000) * Derivatives are now assembled in a slightly different manner (i.e. they might 'look' different on first sight). Under certain circumstances this can result in a dramatic speedup because it gives hashing a better chance, especially when computing higher derivatives. * Some series expansions of built-in functions have been reengineered. * The algorithm for computing determinants can be chosen by the user. See ginac/flags.h and ginac/matrix.h. * The Dilogarithm (Li2) now has floating point evaluation, derivative and a proper series expansion. * Namespace 'std' cleanly disentangled, as demanded by ISO/EIC 14882-1998(E). * Some minor bugfixes, one major lsolve()-bugfix and documentation updates. 0.6.2 (21 June 2000) * ginaccint.bin is now launched by a binary program instead of by a scripts. This allows us to write #!-scripts. A small test suite for GiNaC-cint was added. * Several minor bugfixes. 0.6.1 (18 May 2000) * Cleanup in the interface to Cint. The required version is now Cint 5.14.38. * Several bugfixes in target install. 0.6.0 (11 May 2000) * IMPORTANT: Several interface changes make programs written with GiNaC much clearer but break compatibility with older versions: - f(x).series(x,p[,o]) -> f(x).series(x==p,o) - series(f(x),x,p[,o]) -> series(f(x),x==p,o) - gamma() -> tgamma() (The true Gamma function, there is now also log(tgamma()), called lgamma(), in accord with ISO/IEC 9899:1999.) - EulerGamma -> Euler * #include'ing ginac.h defines the preprocessor symbols GINACLIB_MAJOR_VERSION, GINACLIB_MINOR_VERSION, and GINACLIB_MICRO_VERSION with the respective GiNaC library version numbers. * Expressions can be constructed from strings like this: ex e("2*x+y", lst(x, y)); * ex::to_rational() provides a way to extend the domain of functions like gcd() and divide() that only work on polynomials or rational functions (the good old ex::subs() method reverses this process) * Calling diff() on a function that has no derivative defined returns the inert derivative function "Derivative". * Several new timings in the check target. Some of them may be rather rude at your machine, feel free to interrupt them. 0.5.4 (15 March 2000) * Some algorithms in class matrix (notably determinant) were replaced by less brain-dead ones and should now have much better performance. * Checks were completely reorganized and split up into three parts: a) exams (small regression tests with predefined input) b) checks (lenghty coherence checks with random input) c) timings (for coherence and crude benchmarking) * Behaviour of .evalf() was changed: it doesn't .evalf() any exponents. * Expanded expressions now remember they are expanded to prevent superfluous expansions. * Small bugfixes and improvements in the series expansion. 0.5.3 (23 February 2000) * A more flexible scheme for registering functions was implemented, allowing for remembering, too. * Some Bugfixes. 0.5.2 (16 February 2000) * Mainly fixes a bug in the packaging of release 0.5.1. 0.5.1 (14 February 2000) * Fixes a small number of bugs. 0.5.0 (7 February 2000) * Expressions can be written ("archived") to files and read therefrom. * Addition of GiNaC-cint, which lets you write complete programs in an interactive shell-like manner in your favoured programming language (i.e. C++). 0.4.1 (13 December 1999) * Series Expansion of Gamma function and some other trigonometric functions at their poles works now. * Many more evaluations of special functions at points where exact results exist. * info_flags::rational doesn't return true for complex extensions any more---use info_flags::crational for the old behaviour. info_flags::integer and -::cinteger work similarly, the same holds for types like info_flags::rational_polynomial. 0.4.0 (26 November 1999) * First public release. pynac-pynac-0.6.0/README000066400000000000000000000040101264176364700146320ustar00rootroot00000000000000Pynac -- "Python is Not a CAS" is a modified version of Ginac that replaces the depency of GiNaC on CLN by a dependency instead of Python. It is a lite version of GiNaC as well, not implementing all the features of the full GiNaC, and it is *only* meant to be used as a Python library. -- William Stein ORIGINAL README General Information =================== GiNaC (which stands for "GiNaC is Not a CAS" (computer algebra system)) is a C++ library for symbolic mathematical calculations. It is designed to allow the creation of integrated systems that embed symbolic manipulations together with more established areas of computer science (like computation-intense numeric applications, graphical interfaces, etc.) under one roof. The official ftp site is: ftp://ftpthep.physik.uni-mainz.de/pub/GiNaC/ The official web site is: http://www.ginac.de/ A mailing list is located at: ginac-list@ginac.de You need to be subscribed to be able to post to the list. To subscribe, please follow the instructions on https://www.cebix.net/mailman/listinfo/ginac-list See http://www.ginac.de/Lists.html for the list policy. Installation ============ See the file "INSTALL". How to report bugs ================== If you have identified a bug in GiNaC you are welcome to send a detailed bug report to . Please think about your bug! This means that you should include * Information about your system - Which operating system and version (uname -a) - Which C compiler and version (gcc --version) - For Linux, which version of the C library And anything else you think is relevant. * Information about your version of GiNaC - Version and release number - Which options GiNaC was configured with * How to reproduce the bug - If it is a systematical bug in the library, a short test program together with the output you get and the output you expect will help us to reproduce it quickly. Patches are most welcome. If possible please make them with diff -c and include ChangeLog entries. pynac-pynac-0.6.0/acinclude.m4000066400000000000000000000116111264176364700161500ustar00rootroot00000000000000dnl =========================================================================== dnl Additional macros used to configure GiNaC. We don't start our own dnl additions' names with AC_ but with GINAC_ in order to steer clear of dnl future trouble. dnl =========================================================================== dnl Usage: GINAC_RLVERSION dnl The maintainers of libreadline are complete morons: they don't care a shit dnl about compatiblilty (which is not so bad by itself) and at the same time dnl they don't export the version to the preprocessor so we could kluge around dnl incomatiblities. The only reliable way to figure out the version is by dnl checking the extern variable rl_library_version at runtime. &#@$%*! AC_DEFUN([GINAC_LIB_READLINE_VERSION], [AC_CACHE_CHECK([for version of libreadline], ginac_cv_rlversion, [ AC_TRY_RUN([ #include #include #include int main() { FILE *fd; fd = fopen("conftest.out", "w"); fprintf(fd, "%s\n", rl_library_version); fclose(fd); return 0; }], [ dnl Some non-GNU readline implementations have non-numeric rl_library_version ginac_cv_rlversion=`sed -e 's/[[^0-9.]]//g' 'conftest.out'`], [ ginac_cv_rlversion='unknown'], [ ginac_cv_rlversion='4.2'])]) if test -z "$ginac_cv_rlversion"; then GINAC_WARNING([Unsupported version of libreadline.]) ginac_cv_rlversion='unknown' fi if test "x${ginac_cv_rlversion}" != "xunknown"; then AC_DEFINE(REALLY_HAVE_LIBREADLINE, ,[Define if GNU libreadline is installed]) RL_VERSION_MAJOR=`echo ${ginac_cv_rlversion} | sed -e 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'` AC_DEFINE_UNQUOTED(GINAC_RL_VERSION_MAJOR, $RL_VERSION_MAJOR, [Major version of installed readline library.]) RL_VERSION_MINOR=`echo ${ginac_cv_rlversion} | sed -e 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'` AC_DEFINE_UNQUOTED(GINAC_RL_VERSION_MINOR, $RL_VERSION_MINOR, [Minor version of installed readline library.]) else GINAC_WARNING([I could not run a test of libreadline (needed for building ginsh).]) fi ]) dnl Usage: GINAC_TERMCAP dnl libreadline is based on the termcap functions. dnl Some systems have tgetent(), tgetnum(), tgetstr(), tgetflag(), tputs(), dnl tgoto() in libc, some have it in libtermcap, some have it in libncurses. dnl When both libtermcap and libncurses exist, we prefer the latter, because dnl libtermcap is being phased out. AC_DEFUN([GINAC_TERMCAP], [LIBTERMCAP= case $host_os in *mingw32*) ;; dnl no termcap libraries are necessary (need hacked libreadline) *) AC_CHECK_FUNCS(tgetent) if test "x$ac_cv_func_tgetent" = "xyes"; then : else AC_CHECK_LIB(ncurses, tgetent, LIBTERMCAP="-lncurses") if test -z "$LIBTERMCAP"; then AC_CHECK_LIB(termcap, tgetent, LIBTERMCAP="-ltermcap") fi fi ;; esac AC_SUBST(LIBTERMCAP) ]) dnl Usage: GINAC_ERROR(message) dnl This macro displays the warning "message" and sets the flag ginac_error dnl to yes. AC_DEFUN([GINAC_ERROR],[ ginac_error_txt="$ginac_error_txt ** $1 " ginac_error=yes]) dnl Usage: GINAC_WARNING(message) dnl This macro displays the warning "message" and sets the flag ginac_warning dnl to yes. AC_DEFUN([GINAC_WARNING],[ ginac_warning_txt="$ginac_warning_txt == $1 " ginac_warning=yes]) dnl Usage: GINAC_CHECK_ERRORS dnl (must be put at end of configure.in, because it exits on error) dnl This macro displays a warning message if GINAC_ERROR or GINAC_WARNING dnl has occured previously. AC_DEFUN([GINAC_CHECK_ERRORS],[ if test "x${ginac_error}" = "xyes"; then echo "**** The following problems have been detected by configure." echo "**** Please check the messages below before running \"make\"." echo "**** (see the section 'Common Problems' in the INSTALL file)" echo "$ginac_error_txt" if test "x${ginac_warning_txt}" != "x"; then echo "${ginac_warning_txt}" fi if test "x$cache_file" != "x/dev/null"; then echo "deleting cache ${cache_file}" rm -f $cache_file fi exit 1 else if test "x${ginac_warning}" = "xyes"; then echo "=== The following minor problems have been detected by configure." echo "=== Please check the messages below before running \"make\"." echo "=== (see the section 'Common Problems' in the INSTALL file)" echo "$ginac_warning_txt" fi echo "Configuration of GiNaC $VERSION done. Now type \"make\"." fi]) AC_DEFUN([GINAC_HAVE_RUSAGE], [AC_CACHE_CHECK([whether struct rusage is declared in ], ac_cv_have_rusage, [AC_TRY_COMPILE([#include #include ], [struct rusage resUsage; getrusage(RUSAGE_SELF, &resUsage); return 0;], [ac_cv_have_rusage=yes], [ac_cv_have_rusage=no]) ]) CONFIG_RUSAGE="no" if test "$ac_cv_have_rusage" = yes; then CONFIG_RUSAGE="yes" AC_DEFINE(HAVE_RUSAGE,,[define if struct rusage declared in ]) fi AC_SUBST(CONFIG_RUSAGE) ]) pynac-pynac-0.6.0/bootstrap000077500000000000000000000002001264176364700157120ustar00rootroot00000000000000#!/bin/sh set -e aclocal --force -I m4 libtoolize --copy --force autoconf --force autoheader --force automake --add-missing pynac-pynac-0.6.0/configure.ac000066400000000000000000000134231264176364700162500ustar00rootroot00000000000000dnl Process this file with autoconf to produce a configure script. dnl GiNaC library version information. dnl dnl When making releases do whatever you want with the major, dnl minor and micro project version numbers ; but for the library dnl version, you must be more careful (the following lines are dnl to be read as an algorithm, don't stop at the first one!) : dnl 1. increment lt_revision dnl 2. if any interface has been added, removed or modified since the dnl last release, then increment lt_current and set lt_revision to 0 dnl 3. if any interface has been added, then increment lt_age dnl 4. if any interface has been removed, then set lt_age to zero dnl dnl In case you wonder why such instructions: dnl http://www.sourceware.org/autobook/autobook/autobook_91.html#SEC91 dnl The following article is helpful too: dnl http://www.freesoftwaremagazine.com/articles/building_shared_libraries_once_using_autotools dnl if you change this YOU MUST also change the libtool version below m4_define([ginac_major_version], [0]) m4_define([ginac_minor_version], [6]) m4_define([ginac_micro_version], [0]) m4_define([lt_current], [2]) m4_define([lt_revision], [0]) m4_define([lt_age], [0]) m4_define([ginac_version], [ginac_major_version.ginac_minor_version.ginac_micro_version]) m4_define([ginac_release], [ginac_major_version.ginac_minor_version]) AC_INIT([pynac], ginac_version, []) AC_PREREQ(2.59) AC_CONFIG_SRCDIR(ginac/basic.cpp) AC_CONFIG_HEADERS(config.h) dnl This defines PACKAGE and VERSION. AM_INIT_AUTOMAKE([gnu 1.7 dist-bzip2]) AM_PATH_PYTHON([2.7]) AX_PYTHON_DEVEL AC_CANONICAL_HOST AC_MSG_CHECKING([for Cygwin]) case $host_os in *cygwin*) AM_CONDITIONAL(CYGWIN, true) ;; *) AM_CONDITIONAL(CYGWIN, false) ;; esac AC_MSG_RESULT([$CYGWIN]) dnl use "make V=1" if you want to see the long awful lines m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) dnl keep the correct libtool macros in-tree AC_CONFIG_MACRO_DIR([m4]) dnl Process GiNaC version information GINACLIB_MAJOR_VERSION=ginac_major_version GINACLIB_MINOR_VERSION=ginac_minor_version GINACLIB_MICRO_VERSION=ginac_micro_version GINACLIB_VERSION=ginac_version AC_SUBST(GINACLIB_MAJOR_VERSION) AC_SUBST(GINACLIB_MINOR_VERSION) AC_SUBST(GINACLIB_MICRO_VERSION) AC_SUBST(GINACLIB_VERSION) dnl GiNaC archive file version information. dnl dnl If properties have been added, ARCHIVE_VERSION += 1, ARCHIVE_AGE += 1. dnl If backwards compatibility has been broken, set ARCHIVE_AGE to 0. dnl dnl The version number in newly created archives will be ARCHIVE_VERSION. dnl Archives version (ARCHIVE_VERSION-ARCHIVE_AGE) thru ARCHIVE_VERSION can dnl be read by this version of the GiNaC library. ARCHIVE_VERSION=3 ARCHIVE_AGE=0 AC_SUBST(ARCHIVE_VERSION) AC_SUBST(ARCHIVE_AGE) AC_DEFINE_UNQUOTED(ARCHIVE_VERSION, $ARCHIVE_VERSION, [Current GiNaC archive file version number]) AC_DEFINE_UNQUOTED(ARCHIVE_AGE, $ARCHIVE_AGE, [GiNaC archive file version age]) dnl libtool versioning LT_VERSION_INFO="lt_current:lt_revision:lt_age" AC_SUBST(LT_VERSION_INFO) dnl Check for the compiler and all the utilities needed for the build. AC_PROG_CXX AC_PROG_CXXCPP AC_PROG_INSTALL AM_PROG_LIBTOOL AC_LIBTOOL_WIN32_DLL AC_CHECK_HEADERS([gmp.h], , AC_MSG_ERROR([This package needs gmp headers])) AC_SEARCH_LIBS([__gmpz_get_str], [gmp], [], [AC_MSG_ERROR([This package needs libgmp])]) dnl Check for data types which are needed by the hash function dnl (golden_ratio_hash). AC_CHECK_SIZEOF(int) AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(long long) AC_CHECK_SIZEOF(long double) AC_CHECK_SIZEOF(void *) dnl Switch to C++ language mode for the following libraries and headers. AC_LANG([C++]) AX_CXX_COMPILE_STDCXX_11 dnl Make sure all the necessary standard headers are installed on the system. AC_CHECK_HEADER(iosfwd, , GINAC_ERROR([The standard header file could not be found.])) AC_CHECK_HEADER(iostream, , GINAC_ERROR([The standard header file could not be found.])) AC_CHECK_HEADER(vector, , GINAC_ERROR([The standard header file could not be found.])) AC_CHECK_HEADER(list, , GINAC_ERROR([The standard header file could not be found.])) AC_CHECK_HEADER(map, , GINAC_ERROR([The standard header file could not be found.])) AC_CHECK_HEADER(string, , GINAC_ERROR([The standard header file could not be found.])) AC_CHECK_HEADER(sstream, , GINAC_ERROR([The standard header file could not be found.])) AC_CHECK_HEADER(typeinfo, , GINAC_ERROR([The standard header file could not be found.])) AC_CHECK_HEADER(stdexcept, , GINAC_ERROR([The standard header file could not be found.])) AC_CHECK_HEADER(algorithm, , GINAC_ERROR([The standard header file could not be found.])) AC_CHECK_HEADER(limits, , GINAC_ERROR([The standard header file could not be found.])) if test "x$CONFIG_RUSAGE" = "xno"; then AC_CHECK_HEADER(ctime, , GINAC_ERROR([The standard header file could not be found.])) fi dnl Check for utilities needed by the different kinds of documentation. dnl Documentation needs only be built when extending it, so never mind if it dnl cannot find those helpers: #AC_PATH_PROG(DOXYGEN, doxygen, "") #AM_CONDITIONAL(CONFIG_DOXYGEN, [test ! -z "$DOXYGEN"]) #AC_PATH_PROG(LATEX, latex, "") #AC_PATH_PROG(PDFLATEX, pdflatex, "") #AC_PATH_PROG(MAKEINDEX, makeindex, "") #AC_PATH_PROG(DVIPS, dvips, "") #AM_CONDITIONAL(CONFIG_TEX, [test ! \( -z "$LATEX" -o -z $"PDFLATEX" -o -z "$MAKEINDEX" -o -z "$DVIPS" \)]) #AC_PATH_PROG(FIG2DEV, fig2dev, "") #AM_CONDITIONAL(CONFIG_FIG2DEV, [test ! -z "$FIG2DEV"]) AC_PATH_PROG(RM, rm, $FALSE) RM="$RM -f" dnl Output makefiles etc. AC_CONFIG_FILES([ Makefile pynac.spec pynac.pc ginac/Makefile ginac/version.h ]) AC_OUTPUT dnl Display a final warning if there has been a GINAC_ERROR or a GINAC_WARNING GINAC_CHECK_ERRORS pynac-pynac-0.6.0/ginac/000077500000000000000000000000001264176364700150405ustar00rootroot00000000000000pynac-pynac-0.6.0/ginac/Makefile.am000066400000000000000000000031661264176364700171020ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in lib_LTLIBRARIES = libpynac.la libpynac_la_SOURCES = py_funcs.cpp add.cpp archive.cpp basic.cpp clifford.cpp \ constant.cpp ex.cpp expair.cpp expairseq.cpp exprseq.cpp \ fail.cpp fderivative.cpp function.cpp idx.cpp indexed.cpp infinity.cpp \ inifcns.cpp inifcns_trig.cpp \ inifcns_trans.cpp inifcns_gamma.cpp inifcns_nstdsums.cpp \ integral.cpp lst.cpp matrix.cpp mul.cpp ncmul.cpp normal.cpp numeric.cpp \ operators.cpp power.cpp registrar.cpp relational.cpp remember.cpp \ pseries.cpp print.cpp symbol.cpp symmetry.cpp tensor.cpp \ utils.cpp wildcard.cpp templates.cpp infoflagbase.cpp \ remember.h tostring.h utils.h compiler.h order.cpp assume.cpp #The -no-undefined breaks Pynac on OS X 10.4. See #9135 if CYGWIN libpynac_la_LDFLAGS = -version-info $(LT_VERSION_INFO) -no-undefined else libpynac_la_LDFLAGS = -version-info $(LT_VERSION_INFO) endif libpynac_la_CPPFLAGS = $(PYTHON_CPPFLAGS) -Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wno-unused-parameter libpynac_la_LIBADD = $(PYTHON_LDFLAGS) $(LIBS) ginacincludedir = $(includedir)/pynac ginacinclude_HEADERS = ginac.h py_funcs.h add.h archive.h assertion.h basic.h class_info.h \ clifford.h constant.h infinity.h container.h ex.h expair.h expairseq.h \ exprseq.h fail.h fderivative.h flags.h function.h idx.h indexed.h \ inifcns.h integral.h lst.h matrix.h mul.h ncmul.h normal.h numeric.h operators.h \ power.h print.h pseries.h ptr.h registrar.h relational.h extern_templates.h \ symbol.h symmetry.h tensor.h version.h wildcard.h order.h templates.h \ infoflagbase.h assume.h EXTRA_DIST = version.h.in pynac-pynac-0.6.0/ginac/add.cpp000066400000000000000000000436021264176364700163010ustar00rootroot00000000000000/** @file add.cpp * * Implementation of GiNaC's sums of expressions. */ /* * GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "add.h" #include "mul.h" #include "archive.h" #include "operators.h" #include "matrix.h" #include "utils.h" #include "clifford.h" #include "ncmul.h" #include "constant.h" #include "infinity.h" #include "compiler.h" #include "order.h" #include #include #include #include #include namespace GiNaC { GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(add, expairseq, print_func(&add::do_print). print_func(&add::do_print_latex). print_func(&add::do_print_csrc). print_func(&add::do_print_tree). print_func(&add::do_print_python_repr)) ////////// // default constructor ////////// add::add() { tinfo_key = &add::tinfo_static; } ////////// // other constructors ////////// // public add::add(const ex & lh, const ex & rh) { tinfo_key = &add::tinfo_static; overall_coeff = _ex0; construct_from_2_ex(lh,rh); GINAC_ASSERT(is_canonical()); } add::add(const exvector & v, bool do_hold) { tinfo_key = &add::tinfo_static; overall_coeff = _ex0; construct_from_exvector(v, do_hold); GINAC_ASSERT(is_canonical()); } add::add(const epvector & v) { tinfo_key = &add::tinfo_static; overall_coeff = _ex0; construct_from_epvector(v); GINAC_ASSERT(is_canonical()); } add::add(const epvector & v, const ex & oc) { tinfo_key = &add::tinfo_static; overall_coeff = oc; construct_from_epvector(v); GINAC_ASSERT(is_canonical()); } //add::add(std::unique_ptr vp, const ex & oc) //{ // tinfo_key = &add::tinfo_static; // GINAC_ASSERT(vp.get()!=0); // overall_coeff = oc; // construct_from_epvector(*vp); // GINAC_ASSERT(is_canonical()); //} ////////// // archiving ////////// DEFAULT_ARCHIVING(add) ////////// // functions overriding virtual functions from base classes ////////// // public void add::print_add(const print_context & c, unsigned level, bool latex) const { if (precedence() <= level){ if (latex) c.s << "{\\left("; else c.s << '('; } bool first = true; const epvector & sorted_seq = get_sorted_seq(); // Then proceed with the remaining factors for (const auto & elem : sorted_seq) { std::stringstream tstream; std::unique_ptr tcontext_p; if (latex) { tcontext_p.reset(new print_latex(tstream, c.options)); } else { tcontext_p.reset(new print_dflt(tstream, c.options)); } mul(elem.rest, elem.coeff).print(*tcontext_p, precedence()); if (!first) { if (tstream.peek() == '-') { tstream.ignore(); c.s << " - "; } else c.s << " + "; } else { first = false; } tstream.get(*(c.s.rdbuf())); } // Finally print the "overall" numeric coefficient, if present. // This is just the constant coefficient. if (!(ex_to(overall_coeff)).is_zero()) { std::stringstream tstream; std::unique_ptr tcontext_p; if (latex) { tcontext_p.reset(new print_latex(tstream, c.options)); } else { tcontext_p.reset(new print_dflt(tstream, c.options)); } overall_coeff.print(*tcontext_p, 0); if (!first) { if (tstream.peek() == '-') { c.s << " - "; tstream.ignore(); } else c.s << " + "; } tstream.get(*(c.s.rdbuf())); } if (precedence() <= level) { if (latex) c.s << "\\right)}"; else c.s << ')'; } } void add::do_print(const print_context & c, unsigned level) const { print_add(c, level, false); } void add::do_print_latex(const print_latex & c, unsigned level) const { print_add(c, level, true); } void add::do_print_csrc(const print_csrc & c, unsigned level) const { if (precedence() <= level) c.s << "("; // Print arguments, separated by "+" or "-" char separator = ' '; for (const auto & elem : seq) { // If the coefficient is negative, separator is "-" if (elem.coeff.is_equal(_ex_1) || ex_to(elem.coeff).numer().is_equal(*_num_1_p)) separator = '-'; c.s << separator; if (elem.coeff.is_equal(_ex1) || elem.coeff.is_equal(_ex_1)) { elem.rest.print(c, precedence()); } else if (ex_to(elem.coeff).numer().is_equal(*_num1_p) || ex_to(elem.coeff).numer().is_equal(*_num_1_p)) { elem.rest.print(c, precedence()); c.s << '/'; ex_to(elem.coeff).denom().print(c, precedence()); } else { elem.coeff.print(c, precedence()); c.s << '*'; elem.rest.print(c, precedence()); } separator = '+'; } if (!overall_coeff.is_zero()) { if (overall_coeff.info(info_flags::positive) || is_a(c) || !overall_coeff.info(info_flags::real)) // sign inside ctor argument c.s << '+'; overall_coeff.print(c, precedence()); } if (precedence() <= level) c.s << ")"; } void add::do_print_python_repr(const print_python_repr & c, unsigned) const { c.s << class_name() << '('; op(0).print(c); for (size_t i=1; i::min(); if (!overall_coeff.is_zero()) deg = 0; // Find maximum of degrees of individual terms for (const auto & elem : seq) { int cur_deg = elem.rest.degree(s); if (cur_deg > deg) deg = cur_deg; } return deg; } int add::ldegree(const ex & s) const { int deg = std::numeric_limits::max(); if (!overall_coeff.is_zero()) deg = 0; // Find minimum of degrees of individual terms for (const auto & elem : seq) { int cur_deg = elem.rest.ldegree(s); if (cur_deg < deg) deg = cur_deg; } return deg; } ex add::coeff(const ex & s, int n) const { epvector coeffseq; epvector coeffseq_cliff; int rl = clifford_max_label(s); bool do_clifford = (rl != -1); bool nonscalar = false; // Calculate sum of coefficients in each term for (const auto & elem : seq) { ex restcoeff = elem.rest.coeff(s, n); if (!restcoeff.is_zero()) { if (do_clifford) { if (clifford_max_label(restcoeff) == -1) { coeffseq_cliff.push_back(combine_ex_with_coeff_to_pair(ncmul(restcoeff, dirac_ONE(rl)), elem.coeff)); } else { coeffseq_cliff.push_back(combine_ex_with_coeff_to_pair(restcoeff, elem.coeff)); nonscalar = true; } } coeffseq.push_back(combine_ex_with_coeff_to_pair(restcoeff, elem.coeff)); } } return (new add(nonscalar ? coeffseq_cliff : coeffseq, n==0 ? overall_coeff : _ex0))->setflag(status_flags::dynallocated); } /** Perform automatic term rewriting rules in this class. In the following * x stands for a symbolic variables of type ex and c stands for such * an expression that contain a plain number. * - +(;c) -> c * - +(x;0) -> x * * @param level cut-off in recursive evaluation */ ex add::eval(int level) const { std::unique_ptr evaled_seqp = evalchildren(level); if (evaled_seqp.get()) { // do more evaluation later return (new add(*evaled_seqp, overall_coeff))-> setflag(status_flags::dynallocated); } #ifdef DO_GINAC_ASSERT for (const auto & elem : seq) { GINAC_ASSERT(!is_exactly_a(elem.rest)); if (is_exactly_a(elem.rest)) dbgprint(); GINAC_ASSERT(!is_exactly_a(elem.rest)); } #endif // def DO_GINAC_ASSERT if (flags & status_flags::evaluated) { GINAC_ASSERT(seq.size()>0); GINAC_ASSERT(seq.size()>1 || !overall_coeff.is_zero()); return *this; } // handle infinity for (auto i = seq.begin(); i != seq.end(); i++) if (unlikely(is_exactly_a(i->rest))) return eval_infinity(i); /** Perform automatic term rewriting rules */ int seq_size = seq.size(); if (seq_size == 0) { // +(;c) -> c return overall_coeff; } else if (seq_size == 1 && overall_coeff.is_zero()) { // +(x;0) -> x return recombine_pair_to_ex(*(seq.begin())); } else if (!overall_coeff.is_zero() && seq[0].rest.return_type() != return_types::commutative) { throw (std::logic_error("add::eval(): sum of non-commutative objects has non-zero numeric term")); } // if any terms in the sum still are purely numeric, then they are more // appropriately collected into the overall coefficient int terms_to_collect = 0; for (const auto & elem : seq) if (unlikely(is_exactly_a(elem.rest))) ++terms_to_collect; if (terms_to_collect) { epvector s; s.reserve(seq_size - terms_to_collect); numeric oc = *_num0_p; for (const auto & elem : seq) if (unlikely(is_exactly_a(elem.rest))) oc = oc.add((ex_to(elem.rest)).mul(ex_to(elem.coeff))); else s.push_back(elem); return (new add(s, ex_to(overall_coeff).add_dyn(oc))) ->setflag(status_flags::dynallocated); } return this->hold(); } namespace { // anonymous namespace infinity infinity_from_iter(epvector::const_iterator i) { GINAC_ASSERT(is_exactly_a(i->rest)); GINAC_ASSERT(is_a(i->coeff)); infinity result = ex_to(i->rest); result *= i->coeff; return result; } } // end anonymous namespace ex add::eval_infinity(epvector::const_iterator infinity_iter) const { GINAC_ASSERT(is_exactly_a(infinity_iter->rest)); infinity result = infinity_from_iter(infinity_iter); for (auto i = seq.begin(); i != seq.end(); i++) { if (not is_exactly_a(i->rest)) continue; if (i == infinity_iter) continue; infinity i_infty = infinity_from_iter(i); result += i_infty; } return result; } ex add::evalm() const { // Evaluate children first and add up all matrices. Stop if there's one // term that is not a matrix. epvector s; s.reserve(seq.size()); bool all_matrices = true; bool first_term = true; matrix sum; for (const auto & elem : seq) { const ex &m = recombine_pair_to_ex(elem).evalm(); s.push_back(split_ex_to_pair(m)); if (is_exactly_a(m)) { if (first_term) { sum = ex_to(m); first_term = false; } else sum = sum.add(ex_to(m)); } else all_matrices = false; } if (all_matrices) return sum + overall_coeff; else return (new add(s, overall_coeff))->setflag(status_flags::dynallocated); } ex add::conjugate() const { std::unique_ptr v(nullptr); for (size_t i=0; ipush_back(op(i).conjugate()); continue; } ex term = op(i); ex ccterm = term.conjugate(); if (are_ex_trivially_equal(term, ccterm)) continue; v.reset(new exvector); v->reserve(nops()); for (size_t j=0; jpush_back(op(j)); v->push_back(ccterm); } if (v) { ex result = add(*v); return result; } return *this; } ex add::real_part() const { epvector v; v.reserve(seq.size()); for (const auto & elem : seq) if ((elem.coeff).info(info_flags::real)) { ex rp = (elem.rest).real_part(); if (!rp.is_zero()) v.push_back(expair(rp, elem.coeff)); } else { ex rp=recombine_pair_to_ex(elem).real_part(); if (!rp.is_zero()) 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 (const auto & elem : seq) if ((elem.coeff).info(info_flags::real)) { ex ip = (elem.rest).imag_part(); if (!ip.is_zero()) v.push_back(expair(ip, elem.coeff)); } else { ex ip=recombine_pair_to_ex(elem).imag_part(); if (!ip.is_zero()) 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()) return inherited::eval_ncmul(v); else return seq.begin()->rest.eval_ncmul(v); } // protected /** Implementation of ex::diff() for a sum. It differentiates each term. * @see ex::diff */ ex add::derivative(const symbol & y) const { epvector s; s.reserve(seq.size()); // Only differentiate the "rest" parts of the expairs. This is faster // than the default implementation in basic::derivative() although // if performs the same function (differentiate each term). for (const auto & elem : seq) s.push_back(combine_ex_with_coeff_to_pair(elem.rest.diff(y), elem.coeff)); return (new add(s, _ex0))->setflag(status_flags::dynallocated); } int add::compare_same_type(const basic & other) const { return inherited::compare_same_type(other); } unsigned add::return_type() const { if (seq.empty()) return return_types::commutative; else return seq.begin()->rest.return_type(); } tinfo_t add::return_type_tinfo() const { if (seq.empty()) return this; else return seq.begin()->rest.return_type_tinfo(); } // Note: do_index_renaming is ignored because it makes no sense for an add. ex add::thisexpairseq(const epvector & v, const ex & oc, bool) const { return (new add(v,oc))->setflag(status_flags::dynallocated); } //// Note: do_index_renaming is ignored because it makes no sense for an add. ex add::thisexpairseq(std::unique_ptr vp, const ex & oc, bool) const { return (new add(*vp,oc))->setflag(status_flags::dynallocated); } expair add::split_ex_to_pair(const ex & e) const { if (is_exactly_a(e)) { const mul &mulref(ex_to(e)); const ex &numfactor = mulref.overall_coeff; auto mulcopyp = new mul(mulref); mulcopyp->overall_coeff = _ex1; mulcopyp->clearflag(status_flags::evaluated); mulcopyp->clearflag(status_flags::hash_calculated); mulcopyp->setflag(status_flags::dynallocated); return expair(*mulcopyp,numfactor); } return expair(e,_ex1); } expair add::combine_ex_with_coeff_to_pair(const ex & e, const ex & c) const { GINAC_ASSERT(is_exactly_a(c)); if (is_exactly_a(e)) { const mul &mulref(ex_to(e)); const ex &numfactor = mulref.overall_coeff; auto mulcopyp = new mul(mulref); mulcopyp->overall_coeff = _ex1; mulcopyp->clearflag(status_flags::evaluated); mulcopyp->clearflag(status_flags::hash_calculated); mulcopyp->setflag(status_flags::dynallocated); if (c.is_equal(_ex1)) return expair(*mulcopyp, numfactor); else if (numfactor.is_equal(_ex1)) return expair(*mulcopyp, c); else return expair(*mulcopyp, ex_to(numfactor).mul_dyn(ex_to(c))); } else if (is_exactly_a(e)) { if (c.is_equal(_ex1)) return expair(e, _ex1); return expair(ex_to(e).mul_dyn(ex_to(c)), _ex1); } return expair(e, c); } expair add::combine_pair_with_coeff_to_pair(const expair & p, const ex & c) const { GINAC_ASSERT(is_exactly_a(p.coeff)); GINAC_ASSERT(is_exactly_a(c)); if (is_exactly_a(p.rest)) { GINAC_ASSERT(ex_to(p.coeff).is_equal(*_num1_p)); // should be normalized return expair(ex_to(p.rest).mul_dyn(ex_to(c)),_ex1); } return expair(p.rest,ex_to(p.coeff).mul_dyn(ex_to(c))); } ex add::recombine_pair_to_ex(const expair & p) const { if (ex_to(p.coeff).is_equal(*_num1_p)) return p.rest; else return (new mul(p.rest,p.coeff))->setflag(status_flags::dynallocated); } ex add::expand(unsigned options) const { std::unique_ptr vp = expandchildren(options); if (vp.get() == nullptr) { // the terms have not changed, so it is safe to declare this expanded return (options == 0) ? setflag(status_flags::expanded) : *this; } return (new add(*vp, overall_coeff))->setflag(status_flags::dynallocated | (options == 0 ? status_flags::expanded : 0)); } const epvector & add::get_sorted_seq() const { if (seq_sorted.empty() and not seq.empty()) { seq_sorted = epvector(seq.size()); partial_sort_copy(seq.begin(), seq.end(), seq_sorted.begin(), seq_sorted.end(), print_order_pair()); } return expairseq::get_sorted_seq(); } ex add::lead_coeff() const { // if sorted_seq was computed before, we don't have to search if (seq_sorted.empty() and not seq.empty()) { return min_element(seq.begin(), seq.end(), print_order_pair())->coeff; } else { return seq_sorted.begin()->coeff; } } } // namespace GiNaC pynac-pynac-0.6.0/ginac/add.h000066400000000000000000000070641264176364700157500ustar00rootroot00000000000000/** @file add.h * * Interface to GiNaC's sums of expressions. */ /* * GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __GINAC_ADD_H__ #define __GINAC_ADD_H__ #include "expairseq.h" namespace GiNaC { /** Sum of expressions. */ class add : public expairseq { GINAC_DECLARE_REGISTERED_CLASS(add, expairseq) friend class mul; friend class power; // other constructors public: add(const ex & lh, const ex & rh); add(const exvector & v, bool hold=false); add(const epvector & v); add(const epvector & v, const ex & oc); // add(std::unique_ptr vp, const ex & oc); // functions overriding virtual functions from base classes public: unsigned precedence() const override {return 40;} bool info(unsigned inf) const override; bool is_polynomial(const ex & var) const override; int degree(const ex & s) const override; int ldegree(const ex & s) const override; ex coeff(const ex & s, int n=1) const override; ex eval(int level=0) const override; ex evalm() const override; ex series(const relational & r, int order, unsigned options = 0) const override; ex normal(exmap & repl, exmap & rev_lookup, int level=0) const override; numeric integer_content() const override; ex smod(const numeric &xi) const override; numeric max_coefficient() const override; ex conjugate() const override; ex real_part() const override; ex imag_part() const override; exvector get_free_indices() const override; ex eval_ncmul(const exvector & v) const override; const epvector & get_sorted_seq() const override; ex lead_coeff() const; protected: ex derivative(const symbol & s) const override; unsigned return_type() const override; tinfo_t return_type_tinfo() const override; ex thisexpairseq(const epvector & v, const ex & oc, bool do_index_renaming = false) const override; ex thisexpairseq(std::unique_ptr vp, const ex & oc, bool do_index_renaming = false) const override; expair split_ex_to_pair(const ex & e) const override; expair combine_ex_with_coeff_to_pair(const ex & e, const ex & c) const override; expair combine_pair_with_coeff_to_pair(const expair & p, const ex & c) const override; ex recombine_pair_to_ex(const expair & p) const override; ex expand(unsigned options=0) const override; ex eval_infinity(epvector::const_iterator infinity_iter) const; // non-virtual functions in this class protected: void print_add(const print_context & c, unsigned level, bool latex) const; void do_print(const print_context & c, unsigned level) const override; void do_print_latex(const print_latex & c, unsigned level) const; void do_print_csrc(const print_csrc & c, unsigned level) const; void do_print_python_repr(const print_python_repr & c, unsigned level) const override; }; } // namespace GiNaC #endif // ndef __GINAC_ADD_H__ pynac-pynac-0.6.0/ginac/archive.cpp000066400000000000000000000376261264176364700172030ustar00rootroot00000000000000/** @file archive.cpp * * Archiving of GiNaC expressions. */ /* * GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "archive.h" #include "registrar.h" #include "ex.h" #include "lst.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "tostring.h" #include #include namespace GiNaC { void archive::archive_ex(const ex &e, const char *name) { // Create root node (which recursively archives the whole expression tree) // and add it to the archive archive_node_id id = add_node(archive_node(*this, e)); // Add root node ID to list of archived expressions archived_ex ae = archived_ex(atomize(name), id); exprs.push_back(ae); } /** Add archive_node to archive if the corresponding expression is * not already archived. * @return ID of archived node */ archive_node_id archive::add_node(const archive_node &n) { // Look if expression is known to be in some node already. if (n.has_ex()) { auto i = exprtable.find(n.get_ex()); if (i != exprtable.end()) return i->second; nodes.push_back(n); exprtable[n.get_ex()] = nodes.size() - 1; return nodes.size() - 1; } // Not found, add archive_node to nodes vector nodes.push_back(n); return nodes.size()-1; } /** Retrieve archive_node by ID. */ archive_node &archive::get_node(archive_node_id id) { if (id >= nodes.size()) throw (std::range_error("archive::get_node(): archive node ID out of range")); return nodes[id]; } ex archive::unarchive_ex(const lst &sym_lst, const char *name) const { // Find root node std::string name_string = name; archive_atom id = atomize(name_string); for (const auto & elem : exprs) { if (elem.name == id) { // Recursively unarchive all nodes, starting at the root node lst sym_lst_copy = sym_lst; return nodes[elem.root].unarchive(sym_lst_copy); } } throw (std::runtime_error("expression with name '" + name_string + "' not found in archive")); } ex archive::unarchive_ex(const lst &sym_lst, unsigned index) const { if (index >= exprs.size()) throw (std::range_error("index of archived expression out of range")); // Recursively unarchive all nodes, starting at the root node lst sym_lst_copy = sym_lst; return nodes[exprs[index].root].unarchive(sym_lst_copy); } ex archive::unarchive_ex(const lst &sym_lst, std::string &name, unsigned index) const { if (index >= exprs.size()) throw (std::range_error("index of archived expression out of range")); // Return expression name name = unatomize(exprs[index].name); // Recursively unarchive all nodes, starting at the root node lst sym_lst_copy = sym_lst; return nodes[exprs[index].root].unarchive(sym_lst_copy); } unsigned archive::num_expressions() const { return exprs.size(); } const archive_node &archive::get_top_node(unsigned index) const { if (index >= exprs.size()) throw (std::range_error("index of archived expression out of range")); return nodes[exprs[index].root]; } /* * Archive file format * * - 4 bytes signature 'GARC' * - unsigned version number * - unsigned number of atoms * - atom strings (each zero-terminated) * - unsigned number of expressions * - unsigned name atom * - unsigned root node ID * - unsigned number of nodes * - unsigned number of properties * - unsigned containing type (PTYPE_*) in its lower 3 bits and * name atom in the upper bits * - unsigned property value * * Unsigned quantities are stored in a compressed format: * - numbers in the range 0x00..0x7f are stored verbatim (1 byte) * - numbers larger than 0x7f are stored in 7-bit packets (1 byte per * packet), starting with the LSBs; all bytes except the last one have * their upper bit set * * Examples: * 0x00 = 0x00 * .. .. * 0x7f = 0x7f * 0x80 0x01 = 0x80 * .. .. .. * 0xff 0x01 = 0xff * 0x80 0x02 = 0x100 * .. .. .. * 0xff 0x02 = 0x17f * 0x80 0x03 = 0x180 * .. .. .. * 0xff 0x7f = 0x3fff * 0x80 0x80 0x01 = 0x4000 * .. .. .. .. */ /** Write unsigned integer quantity to stream. */ static void write_unsigned(std::ostream &os, unsigned val) { while (val >= 0x80) { os.put((val & 0x7f) | 0x80); val >>= 7; } os.put(val); } /** Read unsigned integer quantity from stream. */ static unsigned read_unsigned(std::istream &is) { unsigned char b; unsigned ret = 0; unsigned shift = 0; do { char b2; is.get(b2); b = b2; ret |= (b & 0x7f) << shift; shift += 7; } while (b & 0x80); return ret; } /** Write archive_node to binary data stream. */ std::ostream &operator<<(std::ostream &os, const archive_node &n) { // Write properties unsigned num_props = n.props.size(); write_unsigned(os, num_props); for (unsigned i=0; i>(std::istream &is, archive_node &n) { // Read properties unsigned num_props = read_unsigned(is); n.props.resize(num_props); for (unsigned i=0; i> 3; n.props[i].value = read_unsigned(is); } return is; } /** Read archive from binary data stream. */ std::istream &operator>>(std::istream &is, archive &ar) { // Read header char c1, c2, c3, c4; is.get(c1); is.get(c2); is.get(c3); is.get(c4); if (c1 != 'G' || c2 != 'A' || c3 != 'R' || c4 != 'C') throw (std::runtime_error("not a GiNaC archive (signature not found)")); unsigned version = read_unsigned(is); if (version > ARCHIVE_VERSION || version < ARCHIVE_VERSION - ARCHIVE_AGE) throw (std::runtime_error("archive version " + ToString(version) + " cannot be read by this GiNaC library (which supports versions " + ToString(ARCHIVE_VERSION-ARCHIVE_AGE) + " thru " + ToString(ARCHIVE_VERSION))); // Read atoms unsigned num_atoms = read_unsigned(is); ar.atoms.resize(num_atoms); for (unsigned i=0; i> ar.nodes[i]; return is; } /** Atomize a string (i.e. convert it into an ID number that uniquely * represents the string). */ archive_atom archive::atomize(const std::string &s) const { // Search for string in inverse_atoms map. inv_at_cit i = inverse_atoms.find(s); if (i!=inverse_atoms.end()) return i->second; // Not found, add to atoms vector archive_atom id = atoms.size(); atoms.push_back(s); inverse_atoms[s] = id; return id; } /** Unatomize a string (i.e. convert the ID number back to the string). */ const std::string &archive::unatomize(archive_atom id) const { if (id >= atoms.size()) throw (std::range_error("archive::unatomizee(): atom ID out of range")); return atoms[id]; } /** Assignment operator of archive_node. */ const archive_node &archive_node::operator=(const archive_node &other) { if (this != &other) { // archive &a member doesn't get copied props = other.props; has_expression = other.has_expression; e = other.e; } return *this; } /** Recursively construct archive node from expression. */ archive_node::archive_node(archive &ar, const ex &expr) : a(ar), has_expression(true), e(expr) { expr.bp->archive(*this); } /** Check if the archive_node stores the same expression as another * archive_node. * @return "true" if expressions are the same */ bool archive_node::has_same_ex_as(const archive_node &other) const { if (!has_expression || !other.has_expression) return false; return e.bp == other.e.bp; } archive_node::archive_node_cit archive_node::find_first(const std::string &name) const { archive_atom name_atom = a.atomize(name); for (auto i=props.begin(); i!=props.end(); ++i) if (i->name == name_atom) return i; return props.end();; } archive_node::archive_node_cit archive_node::find_last(const std::string &name) const { archive_atom name_atom = a.atomize(name); for (auto i=props.end(); i!=props.begin();) { --i; if (i->name == name_atom) return i; } return props.end(); } void archive_node::add_bool(const std::string &name, bool value) { props.push_back(property(a.atomize(name), PTYPE_BOOL, value)); } void archive_node::add_unsigned(const std::string &name, unsigned value) { props.push_back(property(a.atomize(name), PTYPE_UNSIGNED, value)); } void archive_node::add_string(const std::string &name, const std::string &value) { props.push_back(property(a.atomize(name), PTYPE_STRING, a.atomize(value))); } void archive_node::add_ex(const std::string &name, const ex &value) { // Recursively create an archive_node and add its ID to the properties of this node archive_node_id id = a.add_node(archive_node(a, value)); props.push_back(property(a.atomize(name), PTYPE_NODE, id)); } bool archive_node::find_bool(const std::string &name, bool &ret, unsigned index) const { archive_atom name_atom = a.atomize(name); unsigned found_index = 0; for (const auto & elem : props) { if (elem.type == PTYPE_BOOL && elem.name == name_atom) { if (found_index == index) { ret = elem.value; return true; } found_index++; } } return false; } bool archive_node::find_unsigned(const std::string &name, unsigned &ret, unsigned index) const { archive_atom name_atom = a.atomize(name); unsigned found_index = 0; for (const auto & elem : props) { if (elem.type == PTYPE_UNSIGNED && elem.name == name_atom) { if (found_index == index) { ret = elem.value; return true; } found_index++; } } return false; } bool archive_node::find_string(const std::string &name, std::string &ret, unsigned index) const { archive_atom name_atom = a.atomize(name); unsigned found_index = 0; for (const auto & elem : props) { if (elem.type == PTYPE_STRING && elem.name == name_atom) { if (found_index == index) { ret = a.unatomize(elem.value); return true; } found_index++; } } return false; } void archive_node::find_ex_by_loc(archive_node_cit loc, ex &ret, lst &sym_lst) const { ret = a.get_node(loc->value).unarchive(sym_lst); } bool archive_node::find_ex(const std::string &name, ex &ret, lst &sym_lst, unsigned index) const { archive_atom name_atom = a.atomize(name); unsigned found_index = 0; for (const auto & elem : props) { if (elem.type == PTYPE_NODE && elem.name == name_atom) { if (found_index == index) { ret = a.get_node(elem.value).unarchive(sym_lst); return true; } found_index++; } } return false; } const archive_node &archive_node::find_ex_node(const std::string &name, unsigned index) const { archive_atom name_atom = a.atomize(name); unsigned found_index = 0; for (const auto & elem : props) { if (elem.type == PTYPE_NODE && elem.name == name_atom) { if (found_index == index) return a.get_node(elem.value); found_index++; } } throw (std::runtime_error("property with name '" + name + "' not found in archive node")); } void archive_node::get_properties(propinfovector &v) const { v.clear(); for (const auto & elem : props) { property_type type = elem.type; std::string name = a.unatomize(elem.name); bool found = false; for (auto & velem : v) { if (velem.type == type && velem.name == name) { velem.count++; found = true; break; } } if (!found) v.push_back(property_info(type, name)); } } /** Convert archive node to GiNaC expression. */ ex archive_node::unarchive(lst &sym_lst) const { // Already unarchived? Then return cached unarchived expression. if (has_expression) return e; // Find instantiation function for class specified in node std::string class_name; if (!find_string("class", class_name)) throw (std::runtime_error("archive node contains no class name")); unarch_func f = find_unarch_func(class_name); // Call instantiation function e = f(*this, sym_lst); has_expression = true; return e; } void archive::clear() { atoms.clear(); inverse_atoms.clear(); exprs.clear(); nodes.clear(); exprtable.clear(); } /** Delete cached unarchived expressions in all archive_nodes (mainly for debugging). */ void archive::forget() { for_each(nodes.begin(), nodes.end(), std::mem_fun_ref(&archive_node::forget)); } /** Delete cached unarchived expressions from node (for debugging). */ void archive_node::forget() { has_expression = false; e = 0; } /** Print archive to stream in ugly raw format (for debugging). */ void archive::printraw(std::ostream &os) const { // Dump atoms os << "Atoms:\n"; { archive_atom id = 0; for (const auto & elem : atoms) { os << " " << id << " " << elem << std::endl; id++; } } os << std::endl; // Dump expressions os << "Expressions:\n"; { unsigned index = 0; for (const auto & elem : exprs) { os << " " << index << " \"" << unatomize(elem.name) << "\" root node " << elem.root << std::endl; index++; } } os << std::endl; // Dump nodes os << "Nodes:\n"; { archive_node_id id = 0; for (const auto & elem : nodes) { os << " " << id << " "; elem.printraw(os); id++; } } } /** Output archive_node to stream in ugly raw format (for debugging). */ void archive_node::printraw(std::ostream &os) const { // Dump cached unarchived expression if (has_expression) os << "(basic * " << e.bp << " = " << e << ")\n"; else os << "\n"; // Dump properties for (const auto & elem : props) { os << " "; switch (elem.type) { case PTYPE_BOOL: os << "bool"; break; case PTYPE_UNSIGNED: os << "unsigned"; break; case PTYPE_STRING: os << "string"; break; case PTYPE_NODE: os << "node"; break; default: os << ""; break; } os << " \"" << a.unatomize(elem.name) << "\" " << elem.value << std::endl; } } /** Create a dummy archive. The intention is to fill archive_node's default * ctor, which is currently a Cint-requirement. */ archive* archive_node::dummy_ar_creator() { static auto some_ar = new archive; return some_ar; } } // namespace GiNaC pynac-pynac-0.6.0/ginac/archive.h000066400000000000000000000216501264176364700166360ustar00rootroot00000000000000/** @file archive.h * * Archiving of GiNaC expressions. */ /* * GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __GINAC_ARCHIVE_H__ #define __GINAC_ARCHIVE_H__ #include "ex.h" #include #include #include #include namespace GiNaC { class archive; /** Numerical ID value to refer to an archive_node. */ typedef unsigned archive_node_id; /** Numerical ID value to refer to a string. */ typedef unsigned archive_atom; /** This class stores all properties needed to record/retrieve the state * of one object of class basic (or a derived class). Each property is * addressed by its name and data type. */ class archive_node { friend std::ostream &operator<<(std::ostream &os, const archive_node &ar); friend std::istream &operator>>(std::istream &is, archive_node &ar); public: /** Property data types */ enum property_type { PTYPE_BOOL, PTYPE_UNSIGNED, PTYPE_STRING, PTYPE_NODE }; /** Information about a stored property. A vector of these structures * is returned by get_properties(). * @see get_properties */ struct property_info { property_info() {} property_info(property_type t, std::string n, unsigned c = 1) : type(t), name(std::move(n)), count(c) {} property_type type; /**< Data type of property. */ std::string name; /**< Name of property. */ unsigned count; /**< Number of occurrences. */ }; typedef std::vector propinfovector; /** Archived property (data type, name and associated data) */ struct property { property() {} property(archive_atom n, property_type t, unsigned v) : type(t), name(n), value(v) {} property_type type; /**< Data type of property. */ archive_atom name; /**< Name of property. */ unsigned value; /**< Stored value. */ }; typedef std::vector::const_iterator archive_node_cit; archive_node() : a(*dummy_ar_creator()), has_expression(false) {} // hack for cint which always requires a default constructor archive_node(archive &ar) : a(ar), has_expression(false) {} archive_node(archive &ar, const ex &expr); const archive_node &operator=(const archive_node &other); /** Add property of type "bool" to node. */ void add_bool(const std::string &name, bool value); /** Add property of type "unsigned int" to node. */ void add_unsigned(const std::string &name, unsigned value); /** Add property of type "string" to node. */ void add_string(const std::string &name, const std::string &value); /** Add property of type "ex" to node. */ void add_ex(const std::string &name, const ex &value); /** Retrieve property of type "bool" from node. * @return "true" if property was found, "false" otherwise */ bool find_bool(const std::string &name, bool &ret, unsigned index = 0) const; /** Retrieve property of type "unsigned" from node. * @return "true" if property was found, "false" otherwise */ bool find_unsigned(const std::string &name, unsigned &ret, unsigned index = 0) const; /** Retrieve property of type "string" from node. * @return "true" if property was found, "false" otherwise */ bool find_string(const std::string &name, std::string &ret, unsigned index = 0) const; /** Find the location in the vector of properties of the first/last * property with a given name. */ archive_node_cit find_first(const std::string &name) const; archive_node_cit find_last(const std::string &name) const; /** Retrieve property of type "ex" from node. * @return "true" if property was found, "false" otherwise */ bool find_ex(const std::string &name, ex &ret, lst &sym_lst, unsigned index = 0) const; /** Retrieve property of type "ex" from the node if it is known * that this node in fact contains such a property at the given * location. This is much more efficient than the preceding function. */ void find_ex_by_loc(archive_node_cit loc, ex &ret, lst &sym_lst) const; /** Retrieve property of type "ex" from node, returning the node of * the sub-expression. */ const archive_node &find_ex_node(const std::string &name, unsigned index = 0) const; /** Return vector of properties stored in node. */ void get_properties(propinfovector &v) const; ex unarchive(lst &sym_lst) const; bool has_same_ex_as(const archive_node &other) const; bool has_ex() const {return has_expression;} ex get_ex() const {return e;} void forget(); void printraw(std::ostream &os) const; private: static archive* dummy_ar_creator(); /** Reference to the archive to which this node belongs. */ archive &a; /** Vector of stored properties. */ std::vector props; /** Flag indicating whether a cached unarchived representation of this node exists. */ mutable bool has_expression; /** The cached unarchived representation of this node (if any). */ mutable ex e; }; /** This class holds archived versions of GiNaC expressions (class ex). * An archive can be constructed from an expression and then written to * a stream; or it can be read from a stream and then unarchived, yielding * back the expression. Archives can hold multiple expressions which can * be referred to by name or index number. The main component of the * archive class is a vector of archive_nodes which each store one object * of class basic (or a derived class). */ class archive { friend std::ostream &operator<<(std::ostream &os, const archive &ar); friend std::istream &operator>>(std::istream &is, archive &ar); public: archive() {} ~archive() {} /** Construct archive from expression using the default name "ex". */ archive(const ex &e) {archive_ex(e, "ex");} /** Construct archive from expression using the specified name. */ archive(const ex &e, const char *n) {archive_ex(e, n);} /** Archive an expression. * @param e the expression to be archived * @param name name under which the expression is stored */ void archive_ex(const ex &e, const char *name); /** Retrieve expression from archive by name. * @param sym_lst list of pre-defined symbols * @param name name of expression */ ex unarchive_ex(const lst &sym_lst, const char *name) const; /** Retrieve expression from archive by index. * @param sym_lst list of pre-defined symbols * @param index index of expression * @see count_expressions */ ex unarchive_ex(const lst &sym_lst, unsigned index = 0) const; /** Retrieve expression and its name from archive by index. * @param sym_lst list of pre-defined symbols * @param name receives the name of the expression * @param index index of expression * @see count_expressions */ ex unarchive_ex(const lst &sym_lst, std::string &name, unsigned index = 0) const; /** Return number of archived expressions. */ unsigned num_expressions() const; /** Return reference to top node of an expression specified by index. */ const archive_node &get_top_node(unsigned index = 0) const; /** Clear all archived expressions. */ void clear(); archive_node_id add_node(const archive_node &n); archive_node &get_node(archive_node_id id); void forget(); void printraw(std::ostream &os) const; private: /** Vector of archived nodes. */ std::vector nodes; /** Archived expression descriptor. */ struct archived_ex { archived_ex() {} archived_ex(archive_atom n, archive_node_id node) : name(n), root(node) {} archive_atom name; /**< Name of expression. */ archive_node_id root; /**< ID of root node. */ }; /** Vector of archived expression descriptors. */ std::vector exprs; public: archive_atom atomize(const std::string &s) const; const std::string &unatomize(archive_atom id) const; private: /** Vector of atomized strings (using a vector allows faster unarchiving). */ mutable std::vector atoms; /** The map of from strings to indices of the atoms vectors allows for * faster archiving. */ typedef std::map::const_iterator inv_at_cit; mutable std::map inverse_atoms; /** Map of stored expressions to nodes for faster archiving */ typedef std::map::iterator mapit; mutable std::map exprtable; }; std::ostream &operator<<(std::ostream &os, const archive &ar); std::istream &operator>>(std::istream &is, archive &ar); } // namespace GiNaC #endif // ndef __GINAC_ARCHIVE_H__ pynac-pynac-0.6.0/ginac/assertion.h000066400000000000000000000023301264176364700172160ustar00rootroot00000000000000/** @file assertion.h * * Assertion macro definition. */ /* * GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __GINAC_ASSERTION_H__ #define __GINAC_ASSERTION_H__ #if !defined(GINAC_ASSERT) #if defined(DO_GINAC_ASSERT) #include /** Assertion macro for checking invariances. */ #define GINAC_ASSERT(X) assert(X) #else /** Assertion macro for checking invariances. */ #define GINAC_ASSERT(X) ((void)0) #endif #endif #endif // ndef __GINAC_ASSERTION_H__ pynac-pynac-0.6.0/ginac/assume.cpp000066400000000000000000000027261264176364700170500ustar00rootroot00000000000000/* * File: assume.cpp * Author: Ralf Stephan * * Created on August 5, 2015, 9:31 AM */ #include "ex.h" #include "operators.h" #include "symbol.h" #include "function.h" #include "relational.h" #include "utils.h" #include "flags.h" #include "infoflagbase.h" namespace GiNaC { void assume(ex rel) { // It was already checked that rel is a relational. relational r = ex_to(rel); if (r.the_operator() == relational::equal or r.the_operator() == relational::not_equal) return; ex df = (r.lhs() - r.rhs()).expand(); if (r.the_operator() == relational::greater) df.set_domain(domain::positive); } void assume(ex x, char* flag_desc) { if (!strcmp(flag_desc, "integer")) x.set_domain(domain::integer); else if (!strcmp(flag_desc, "real")) x.set_domain(domain::real); else if (!strcmp(flag_desc, "complex")) x.set_domain(domain::complex); } void forget(ex rel) { // It was already checked that rel is a relational. relational r = ex_to(rel); if (r.the_operator() == relational::equal or r.the_operator() == relational::not_equal) return; ex df = (r.lhs() - r.rhs()).expand(); df.set_domain(domain::complex); } void forget(ex x, char* flag_desc) { x.set_domain(domain::complex); } } // namespace GiNaC pynac-pynac-0.6.0/ginac/assume.h000066400000000000000000000005141264176364700165060ustar00rootroot00000000000000/* * File: assume.h * Author: Ralf Stephan * * Created on August 5, 2015, 7:22 AM */ #ifndef ASSUME_H #define ASSUME_H namespace GiNaC { void assume(ex rel); void assume(ex x, char* flag_desc); void forget(ex rel); void forget(ex x, char* flag_desc); } // namespace GiNaC #endif /* ASSUME_H */ pynac-pynac-0.6.0/ginac/basic.cpp000066400000000000000000000657261264176364700166450ustar00rootroot00000000000000/** @file basic.cpp * * Implementation of GiNaC's ABC. */ /* * GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "basic.h" #include "ex.h" #include "numeric.h" #include "power.h" #include "add.h" #include "symbol.h" #include "lst.h" #include "ncmul.h" #include "relational.h" #include "operators.h" #include "wildcard.h" #include "archive.h" #include "utils.h" #include "inifcns.h" #include #include #ifdef DO_GINAC_ASSERT # include #endif namespace GiNaC { GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(basic, void, print_func(&basic::do_print). print_func(&basic::do_print_tree). print_func(&basic::do_print_python_repr)) ////////// // default constructor, destructor, copy constructor and assignment operator ////////// // public /** basic copy constructor: implicitly assumes that the other class is of * the exact same type (as it's used by duplicate()), so it can copy the * tinfo_key and the hash value. */ basic::basic(const basic & other) : tinfo_key(other.tinfo_key), flags(other.flags & ~status_flags::dynallocated), hashvalue(other.hashvalue) { } /** basic assignment operator: the other object might be of a derived class. */ const basic & basic::operator=(const basic & other) { unsigned fl = other.flags & ~status_flags::dynallocated; if (tinfo_key != other.tinfo_key) { // The other object is of a derived class, so clear the flags as they // might no longer apply (especially hash_calculated). Oh, and don't // copy the tinfo_key: it is already set correctly for this object. fl &= ~(status_flags::evaluated | status_flags::expanded | status_flags::hash_calculated); } else { // The objects are of the exact same class, so copy the hash value. hashvalue = other.hashvalue; } flags = fl; set_refcount(0); return *this; } // protected // none (all inlined) ////////// // other constructors ////////// // none (all inlined) ////////// // archiving ////////// /** Construct object from archive_node. */ basic::basic(const archive_node &n, lst&) : flags(0) { // Reconstruct tinfo_key from class name std::string found_class_name; if (n.find_string("class", found_class_name)) tinfo_key = find_tinfo_key(found_class_name); else throw (std::runtime_error("archive node contains no class name")); } /** Unarchive the object. */ DEFAULT_UNARCHIVE(basic) /** Archive the object. */ void basic::archive(archive_node &n) const { n.add_string("class", class_name()); } ////////// // new virtual functions which can be overridden by derived classes ////////// // public /** Output to stream. This performs double dispatch on the dynamic type of * *this and the dynamic type of the supplied print context. * @param c print context object that describes the output formatting * @param level value that is used to identify the precedence or indentation * level for placing parentheses and formatting */ void basic::print(const print_context & c, unsigned level) const { print_dispatch(get_class_info(), c, level); } /** Like print(), but dispatch to the specified class. Can be used by * implementations of print methods to dispatch to the method of the * superclass. * * @see basic::print */ void basic::print_dispatch(const registered_class_info & ri, const print_context & c, unsigned level) const { // Double dispatch on object type and print_context type const registered_class_info * reg_info = &ri; const print_context_class_info * pc_info = &c.get_class_info(); next_class: const std::vector & pdt = reg_info->options.get_print_dispatch_table(); next_context: unsigned id = pc_info->options.get_id(); if (id >= pdt.size() || !(pdt[id].is_valid())) { // Method not found, try parent print_context class const print_context_class_info * parent_pc_info = pc_info->get_parent(); if (parent_pc_info) { pc_info = parent_pc_info; goto next_context; } // Method still not found, try parent class const registered_class_info * parent_reg_info = reg_info->get_parent(); if (parent_reg_info) { reg_info = parent_reg_info; pc_info = &c.get_class_info(); goto next_class; } // Method still not found. This shouldn't happen because basic (the // base class of the algebraic hierarchy) registers a method for // print_context (the base class of the print context hierarchy), // so if we end up here, there's something wrong with the class // registry. throw (std::runtime_error(std::string("basic::print(): method for ") + class_name() + "/" + c.class_name() + " not found")); } else { // Call method pdt[id](*this, c, level); } } /** Default output to stream. */ void basic::do_print(const print_context & c, unsigned) const { c.s << "[" << class_name() << " object]"; } /** Tree output to stream. */ void basic::do_print_tree(const print_tree & c, unsigned level) const { c.s << std::string(level, ' ') << class_name() << " @" << this << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec; if (nops()) c.s << ", nops=" << nops(); c.s << std::endl; for (size_t i=0; iprint(print_dflt(std::cerr)); std::cerr << std::endl; } /** Little wrapper around printtree to be called within a debugger. * * @see basic::dbgprint */ void basic::dbgprinttree() const { this->print(print_tree(std::cerr)); } /** Return relative operator precedence (for parenthezing output). */ unsigned basic::precedence() const { return 70; } /** Information about the object. * * @see class info_flags */ bool basic::info(unsigned) const { // all possible properties are false for basic objects return false; } /** Number of operands/members. */ size_t basic::nops() const { // iterating from 0 to nops() on atomic objects should be an empty loop, // and accessing their elements is a range error. Container objects should // override this. return 0; } /** Return operand/member at position i. */ ex basic::op(size_t) const { throw(std::range_error(std::string("basic::op(): ") + class_name() + std::string(" has no operands"))); } /** Return modifyable operand/member at position i. */ ex & basic::let_op(size_t) { ensure_if_modifiable(); throw(std::range_error(std::string("basic::let_op(): ") + class_name() + std::string(" has no operands"))); } ex basic::operator[](const ex & index) const { if (is_exactly_a(index)) return op(static_cast(ex_to(index).to_int())); throw(std::invalid_argument(std::string("non-numeric indices not supported by ") + class_name())); } ex basic::operator[](size_t i) const { return op(i); } ex & basic::operator[](const ex & index) { if (is_exactly_a(index)) return let_op(ex_to(index).to_int()); throw(std::invalid_argument(std::string("non-numeric indices not supported by ") + class_name())); } ex & basic::operator[](size_t i) { return let_op(i); } /** Test for occurrence of a pattern. An object 'has' a pattern if it matches * the pattern itself or one of the children 'has' it. As a consequence * (according to the definition of children) given e=x+y+z, e.has(x) is true * but e.has(x+y) is false. */ bool basic::has(const ex & pattern, unsigned options) const { lst repl_lst; if (match(pattern, repl_lst)) return true; for (size_t i=0; ilet_op(i) = n; } } if (copy) { copy->setflag(status_flags::dynallocated); copy->clearflag(status_flags::hash_calculated | status_flags::expanded); return *copy; } else return *this; } /** Check whether this is a polynomial in the given variables. */ bool basic::is_polynomial(const ex & var) const { return !has(var) || is_equal(ex_to(var)); } /** Return degree of highest power in object s. */ int basic::degree(const ex & s) const { return is_equal(ex_to(s)) ? 1 : 0; } /** Return degree of lowest power in object s. */ int basic::ldegree(const ex & s) const { return is_equal(ex_to(s)) ? 1 : 0; } /** Return coefficient of degree n in object s. */ ex basic::coeff(const ex & s, int n) const { if (is_equal(ex_to(s))) return n==1 ? _ex1 : _ex0; else return n==0 ? *this : _ex0; } /** Sort expanded expression in terms of powers of some object(s). * @param s object(s) to sort in * @param distributed recursive or distributed form (only used when s is a list) */ ex basic::collect(const ex & s, bool distributed) const { ex x; if (is_exactly_a(s)) { // List of objects specified if (s.nops() == 0) return *this; if (s.nops() == 1) return collect(s.op(0)); else if (distributed) { x = this->expand(); if (! is_exactly_a(x)) return x; const lst& l(ex_to(s)); exmap cmap; cmap[_ex1] = _ex0; for (const auto & xelem : x) { ex key = _ex1; ex pre_coeff = xelem; for (const auto & lelem : l) { int cexp = pre_coeff.degree(lelem); pre_coeff = pre_coeff.coeff(lelem, cexp); key *= pow(lelem, cexp); } auto ci = cmap.find(key); if (ci != cmap.end()) ci->second += pre_coeff; else cmap.insert(exmap::value_type(key, pre_coeff)); } exvector resv; for (const auto & elem : cmap) resv.push_back((elem.first) * (elem.second)); return (new add(resv))->setflag(status_flags::dynallocated); } else { // Recursive form x = *this; size_t n = s.nops() - 1; while (true) { x = x.collect(s[n]); if (n == 0) break; n--; } } } else { // Only one object specified for (int n=this->ldegree(s); n<=this->degree(s); ++n) x += this->coeff(s,n)*power(s,n); } // correct for lost fractional arguments and return return x + (*this - x).expand(); } /** Perform automatic non-interruptive term rewriting rules. */ ex basic::eval(int) const { // There is nothing to do for basic objects: return hold(); } /** Function object to be applied by basic::evalf(). */ struct evalf_map_function : public map_function { int level; PyObject* parent; evalf_map_function(int l, PyObject* p) : level(l), parent(p) {} ex operator()(const ex & e) override { return evalf(e, level, parent); } }; /** Evaluate object numerically. */ ex basic::evalf(int level, PyObject* parent) const { if (nops() == 0) return *this; else { if (level == 1) return *this; else if (level == -max_recursion_level) throw(std::runtime_error("max recursion level reached")); else { evalf_map_function map_evalf(level - 1, parent); return map(map_evalf); } } } /** Function object to be applied by basic::evalm(). */ struct evalm_map_function : public map_function { ex operator()(const ex & e) override { return evalm(e); } } map_evalm; /** Evaluate sums, products and integer powers of matrices. */ ex basic::evalm() const { if (nops() == 0) return *this; else return map(map_evalm); } /** Function object to be applied by basic::eval_integ(). */ struct eval_integ_map_function : public map_function { ex operator()(const ex & e) override { return eval_integ(e); } } map_eval_integ; /** Evaluate integrals, if result is known. */ ex basic::eval_integ() const { if (nops() == 0) return *this; else return map(map_eval_integ); } /** Perform automatic symbolic evaluations on indexed expression that * contains this object as the base expression. */ ex basic::eval_indexed(const basic & i) const // this function can't take a "const ex & i" because that would result // in an infinite eval() loop { // There is nothing to do for basic objects return i.hold(); } /** Add two indexed expressions. They are guaranteed to be of class indexed * (or a subclass) and their indices are compatible. This function is used * internally by simplify_indexed(). * * @param self First indexed expression; its base object is *this * @param other Second indexed expression * @return sum of self and other * @see ex::simplify_indexed() */ ex basic::add_indexed(const ex & self, const ex & other) const { return self + other; } /** Multiply an indexed expression with a scalar. This function is used * internally by simplify_indexed(). * * @param self Indexed expression; its base object is *this * @param other Numeric value * @return product of self and other * @see ex::simplify_indexed() */ ex basic::scalar_mul_indexed(const ex & self, const numeric & other) const { return self * other; } /** Try to contract two indexed expressions that appear in the same product. * If a contraction exists, the function overwrites one or both of the * expressions and returns true. Otherwise it returns false. It is * guaranteed that both expressions are of class indexed (or a subclass) * and that at least one dummy index has been found. This functions is * used internally by simplify_indexed(). * * @param self Pointer to first indexed expression; its base object is *this * @param other Pointer to second indexed expression * @param v The complete vector of factors * @return true if the contraction was successful, false otherwise * @see ex::simplify_indexed() */ bool basic::contract_with(exvector::iterator, exvector::iterator, exvector&) const { // Do nothing return false; } /** Check whether the expression matches a given pattern. For every wildcard * object in the pattern, an expression of the form "wildcard == matching_expression" * is added to repl_lst. */ bool basic::match(const ex & pattern, lst & repl_lst) const { /* Sweet sweet shapes, sweet sweet shapes, That's the key thing, right right. Feed feed face, feed feed shapes, But who is the king tonight? Who is the king tonight? Pattern is the thing, the key thing-a-ling, But who is the king of Pattern? But who is the king, the king thing-a-ling, Who is the king of Pattern? Bog is the king, the king thing-a-ling, Bog is the king of Pattern. Ba bu-bu-bu-bu bu-bu-bu-bu-bu-bu bu-bu Bog is the king of Pattern. */ if (is_exactly_a(pattern)) { // Wildcard matches anything, but check whether we already have found // a match for that wildcard first (if so, the earlier match must be // the same expression) for (const auto & elem : repl_lst) { if (elem.op(0).is_equal(pattern)) return is_equal(ex_to(elem.op(1))); } repl_lst.append(pattern == *this); return true; } else { // Expression must be of the same type as the pattern if (tinfo() != ex_to(pattern).tinfo()) return false; // Number of subexpressions must match if (nops() != pattern.nops()) return false; // No subexpressions? Then just compare the objects (there can't be // wildcards in the pattern) if (nops() == 0) return is_equal_same_type(ex_to(pattern)); // Check whether attributes that are not subexpressions match if (!match_same_type(ex_to(pattern))) return false; // Otherwise the subexpressions must match one-to-one for (size_t i=0; isecond : *this; } else { for (const auto & elem : m) { lst repl_lst; if (match(ex_to(elem.first), repl_lst)) return elem.second.subs(repl_lst, options | subs_options::no_pattern); // avoid infinite recursion when re-substituting the wildcards } } return *this; } /** Substitute a set of objects by arbitrary expressions. The ex returned * will already be evaluated. */ ex basic::subs(const exmap & m, unsigned options) const { size_t num = nops(); if (num) { // Substitute in subexpressions for (size_t i=0; isetflag(status_flags::dynallocated); copy->clearflag(status_flags::hash_calculated | status_flags::expanded); // Substitute the changed operand copy->let_op(i++) = subsed_op; // Substitute the other operands for (; ilet_op(i) = op(i).subs(m, options); // Perform substitutions on the new object as a whole return copy->subs_one_level(m, options); } } } // Nothing changed or no subexpressions return subs_one_level(m, options); } /** Default interface of nth derivative ex::diff(s, n). It should be called * instead of ::derivative(s) for first derivatives and for nth derivatives it * just recurses down. * * @param s symbol to differentiate in * @param nth order of differentiation * @see ex::diff */ ex basic::diff(const symbol & s, unsigned nth) const { // trivial: zeroth derivative if (nth==0) return ex(*this); // evaluate unevaluated *this before differentiating if (!(flags & status_flags::evaluated)) return ex(*this).diff(s, nth); ex ndiff = this->derivative(s); while (!ndiff.is_zero() && // stop differentiating zeros nth>1) { ndiff = ndiff.diff(s); --nth; } return ndiff; } /** Return a vector containing the free indices of an expression. */ exvector basic::get_free_indices() const { return exvector(); // return an empty exvector } 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); } // protected /** Function object to be applied by basic::derivative(). */ struct derivative_map_function : public map_function { const symbol &s; derivative_map_function(const symbol &sym) : s(sym) {} ex operator()(const ex & e) override { return diff(e, s); } }; /** Default implementation of ex::diff(). It maps the operation on the * operands (or returns 0 when the object has no operands). * * @see ex::diff */ ex basic::derivative(const symbol & s) const { if (nops() == 0) return _ex0; else { derivative_map_function map_derivative(s); return map(map_derivative); } } /** Returns order relation between two objects of same type. This needs to be * implemented by each class. It may never return anything else than 0, * signalling equality, or +1 and -1 signalling inequality and determining * the canonical ordering. (Perl hackers will wonder why C++ doesn't feature * the spaceship operator <=> for denoting just this.) */ int basic::compare_same_type(const basic & other) const { return compare_pointers(this, &other); } /** Returns true if two objects of same type are equal. Normally needs * not be reimplemented as long as it wasn't overwritten by some parent * class, since it just calls compare_same_type(). The reason why this * function exists is that sometimes it is easier to determine equality * than an order relation and then it can be overridden. */ bool basic::is_equal_same_type(const basic & other) const { return compare_same_type(other)==0; } /** Returns true if the attributes of two objects are similar enough for * a match. This function must not match subexpressions (this is already * done by basic::match()). Only attributes not accessible by op() should * be compared. This is also the reason why this function doesn't take the * wildcard replacement list from match() as an argument: only subexpressions * are subject to wildcard matches. Also, this function only needs to be * implemented for container classes because is_equal_same_type() is * automatically used instead of match_same_type() if nops() == 0. * * @see basic::match */ bool basic::match_same_type(const basic &) const { // The default is to only consider subexpressions, but not any other // attributes return true; } unsigned basic::return_type() const { return return_types::commutative; } tinfo_t basic::return_type_tinfo() const { return tinfo_key; } /** Compute the hash value of an object and if it makes sense to store it in * the objects status_flags, do so. The method inherited from class basic * computes a hash value based on the type and hash values of possible * members. For this reason it is well suited for container classes but * atomic classes should override this implementation because otherwise they * would all end up with the same hashvalue. */ long basic::calchash() const { long v = golden_ratio_hash((p_int)tinfo()); for (size_t i=0; iop(i).gethash(); } // store calculated hash value only if object is already evaluated if (flags & status_flags::evaluated) { setflag(status_flags::hash_calculated); hashvalue = v; } return v; } /** Function object to be applied by basic::expand(). */ struct expand_map_function : public map_function { unsigned options; expand_map_function(unsigned o) : options(o) {} ex operator()(const ex & e) override { return e.expand(options); } }; /** Expand expression, i.e. multiply it out and return the result as a new * expression. */ ex basic::expand(unsigned options) const { if (nops() == 0) return (options == 0) ? setflag(status_flags::expanded) : *this; else { expand_map_function map_expand(options); return ex_to(map(map_expand)).setflag(options == 0 ? status_flags::expanded : 0); } } ////////// // non-virtual functions in this class ////////// // public /** Compare objects syntactically to establish canonical ordering. * All compare functions return: -1 for *this less than other, 0 equal, * 1 greater. */ int basic::compare(const basic & other) const { #ifdef GINAC_COMPARE_STATISTICS compare_statistics.total_basic_compares++; #endif const long hash_this = gethash(); const long hash_other = other.gethash(); if (hash_thishash_other) return 1; #ifdef GINAC_COMPARE_STATISTICS compare_statistics.compare_same_hashvalue++; #endif const tinfo_t& typeid_this = tinfo();//typeid(*this); const tinfo_t& typeid_other = other.tinfo();//typeid(other); if (typeid_this == typeid_other) { // int cmpval = compare_same_type(other); // if (cmpval!=0) { // std::cout << "hash collision, same type: " // << *this << " and " << other << std::endl; // this->print(print_tree(std::cout)); // std::cout << " and "; // other.print(print_tree(std::cout)); // std::cout << std::endl; // } // return cmpval; #ifdef GINAC_COMPARE_STATISTICS compare_statistics.compare_same_type++; #endif return compare_same_type(other); } else { // std::cout << "hash collision, different types: " // << *this << " and " << other << std::endl; // this->print(print_tree(std::cout)); // std::cout << " and "; // other.print(print_tree(std::cout)); // std::cout << std::endl; //return (typeid_this.before(typeid_other) ? -1 : 1); return (typeid_thisgethash()!=other.gethash()) return false; #ifdef GINAC_COMPARE_STATISTICS compare_statistics.is_equal_same_hashvalue++; #endif if (this->tinfo()!=other.tinfo()) return false; GINAC_ASSERT(typeid(*this)==typeid(other)); #ifdef GINAC_COMPARE_STATISTICS compare_statistics.is_equal_same_type++; #endif return is_equal_same_type(other); } // protected /** Stop further evaluation. * * @see basic::eval */ const basic & basic::hold() const { return setflag(status_flags::evaluated); } /** Ensure the object may be modified without hurting others, throws if this * is not the case. */ void basic::ensure_if_modifiable() const { if (get_refcount() > 1) throw(std::runtime_error("cannot modify multiply referenced object")); clearflag(status_flags::hash_calculated | status_flags::evaluated); } ////////// // global variables ////////// int max_recursion_level = 1024; #ifdef GINAC_COMPARE_STATISTICS compare_statistics_t::~compare_statistics_t() { std::clog << "ex::compare() called " << total_compares << " times" << std::endl; std::clog << "nontrivial compares: " << nontrivial_compares << " times" << std::endl; std::clog << "basic::compare() called " << total_basic_compares << " times" << std::endl; std::clog << "same hashvalue in compare(): " << compare_same_hashvalue << " times" << std::endl; std::clog << "compare_same_type() called " << compare_same_type << " times" << std::endl; std::clog << std::endl; std::clog << "ex::is_equal() called " << total_is_equals << " times" << std::endl; std::clog << "nontrivial is_equals: " << nontrivial_is_equals << " times" << std::endl; std::clog << "basic::is_equal() called " << total_basic_is_equals << " times" << std::endl; std::clog << "same hashvalue in is_equal(): " << is_equal_same_hashvalue << " times" << std::endl; std::clog << "is_equal_same_type() called " << is_equal_same_type << " times" << std::endl; std::clog << std::endl; std::clog << "basic::gethash() called " << total_gethash << " times" << std::endl; std::clog << "used cached hashvalue " << gethash_cached << " times" << std::endl; } compare_statistics_t compare_statistics; #endif } // namespace GiNaC pynac-pynac-0.6.0/ginac/basic.h000066400000000000000000000222751264176364700163020ustar00rootroot00000000000000/** @file basic.h * * Interface to GiNaC's ABC. */ /* * GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __GINAC_BASIC_H__ #define __GINAC_BASIC_H__ #include #include // for size_t #include #include #include // CINT needs to work properly with #include #include "flags.h" #include "ptr.h" #include "assertion.h" #include "registrar.h" namespace GiNaC { class ex; class ex_is_less; class symbol; class numeric; class relational; class archive_node; class print_context; typedef std::vector exvector; typedef std::set exset; typedef std::map exmap; // Define this to enable some statistical output for comparisons and hashing #undef GINAC_COMPARE_STATISTICS #ifdef GINAC_COMPARE_STATISTICS class compare_statistics_t { public: compare_statistics_t() : total_compares(0), nontrivial_compares(0), total_basic_compares(0), compare_same_hashvalue(0), compare_same_type(0), total_is_equals(0), nontrivial_is_equals(0), total_basic_is_equals(0), is_equal_same_hashvalue(0), is_equal_same_type(0), total_gethash(0), gethash_cached(0) {} ~compare_statistics_t(); unsigned long total_compares; unsigned long nontrivial_compares; unsigned long total_basic_compares; unsigned long compare_same_hashvalue; unsigned long compare_same_type; unsigned long total_is_equals; unsigned long nontrivial_is_equals; unsigned long total_basic_is_equals; unsigned long is_equal_same_hashvalue; unsigned long is_equal_same_type; unsigned long total_gethash; unsigned long gethash_cached; }; extern compare_statistics_t compare_statistics; #endif /** Function object for map(). */ struct map_function { virtual ~map_function() {} typedef const ex & argument_type; typedef ex result_type; virtual ex operator()(const ex & e) = 0; }; /** Degenerate base class for visitors. basic and derivative classes * support Robert C. Martin's Acyclic Visitor pattern (cf. * http://objectmentor.com/publications/acv.pdf). */ class visitor { protected: virtual ~visitor() {} }; /** This class is the ABC (abstract base class) of GiNaC's class hierarchy. */ class basic : public refcounted { GINAC_DECLARE_REGISTERED_CLASS_NO_CTORS(basic, void) friend class ex; friend struct print_order; friend struct print_order_pair; // default constructor, destructor, copy constructor and assignment operator protected: basic() : tinfo_key(&tinfo_static), flags(0) {} public: /** basic destructor, virtual because class ex will delete objects of * derived classes via a basic*. */ virtual ~basic() { GINAC_ASSERT((!(flags & status_flags::dynallocated)) || (get_refcount() == 0)); } basic(const basic & other); const basic & operator=(const basic & other); protected: /** Constructor with specified tinfo_key (used by derived classes instead * of the default constructor to avoid assigning tinfo_key twice). */ basic(tinfo_t ti) : tinfo_key(ti), flags(0) {} // new virtual functions which can be overridden by derived classes public: // only const functions please (may break reference counting) /** Create a clone of this object on the heap. One can think of this as * simulating a virtual copy constructor which is needed for instance by * the refcounted construction of an ex from a basic. */ virtual basic * duplicate() const { return new basic(*this); } // evaluation virtual ex eval(int level = 0) const; virtual ex evalf(int level = 0, PyObject* parent=nullptr) const; virtual ex evalm() const; virtual ex eval_integ() const; protected: virtual ex eval_ncmul(const exvector & v) const; public: virtual ex eval_indexed(const basic & i) const; // printing virtual void print(const print_context & c, unsigned level = 0) const; virtual void dbgprint() const; virtual void dbgprinttree() const; virtual unsigned precedence() const; // info virtual bool info(unsigned inf) const; // operand access virtual size_t nops() const; virtual ex op(size_t i) const; virtual ex operator[](const ex & index) const; virtual ex operator[](size_t i) const; virtual ex & let_op(size_t i); virtual ex & operator[](const ex & index); virtual ex & operator[](size_t i); // pattern matching virtual bool has(const ex & other, unsigned options = 0) const; virtual bool match(const ex & pattern, lst & repl_lst) const; protected: virtual bool match_same_type(const basic & other) const; virtual void do_print(const print_context & c, unsigned level) const; virtual void do_print_tree(const print_tree & c, unsigned level) const; virtual void do_print_python_repr(const print_python_repr & c, unsigned level) const; public: // substitutions virtual ex subs(const exmap & m, unsigned options = 0) const; // function mapping virtual ex map(map_function & f) const; // visitors and tree traversal virtual void accept(GiNaC::visitor & v) const { if (visitor *p = dynamic_cast(&v)) p->visit(*this); } // degree/coeff virtual bool is_polynomial(const ex & var) const; virtual int degree(const ex & s) const; virtual int ldegree(const ex & s) const; virtual ex coeff(const ex & s, int n = 1) const; // expand/collect virtual ex expand(unsigned options = 0) const; virtual ex collect(const ex & s, bool distributed = false) const; // differentiation and series expansion protected: virtual ex derivative(const symbol & s) const; public: virtual ex series(const relational & r, int order, unsigned options = 0) const; // rational functions virtual ex normal(exmap & repl, exmap & rev_lookup, int level = 0) const; virtual ex to_rational(exmap & repl) const; virtual ex to_polynomial(exmap & repl) const; // polynomial algorithms virtual numeric integer_content() const; virtual ex smod(const numeric &xi) const; virtual numeric max_coefficient() const; // indexed objects virtual exvector get_free_indices() const; virtual ex add_indexed(const ex & self, const ex & other) const; virtual ex scalar_mul_indexed(const ex & self, const numeric & other) const; virtual bool contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const; // noncommutativity virtual unsigned return_type() const; virtual tinfo_t return_type_tinfo() const; // functions for complex expressions virtual ex conjugate() const; virtual ex real_part() const; virtual ex imag_part() const; virtual int compare(const basic & other) const; // functions that should be called from class ex only protected: virtual int compare_same_type(const basic & other) const; virtual bool is_equal_same_type(const basic & other) const; virtual long calchash() const; // non-virtual functions in this class public: /** Like print(), but dispatch to the specified class. Can be used by * implementations of print methods to dispatch to the method of the * superclass. * * @see basic::print */ template void print_dispatch(const print_context & c, unsigned level) const { print_dispatch(T::get_class_info_static(), c, level); } void print_dispatch(const registered_class_info & ri, const print_context & c, unsigned level) const; ex subs_one_level(const exmap & m, unsigned options) const; ex diff(const symbol & s, unsigned nth = 1) const; bool is_equal(const basic & other) const; const basic & hold() const; long gethash() const { #ifdef GINAC_COMPARE_STATISTICS compare_statistics.total_gethash++; #endif if (flags & status_flags::hash_calculated) { #ifdef GINAC_COMPARE_STATISTICS compare_statistics.gethash_cached++; #endif return hashvalue; } else { return calchash(); } } tinfo_t tinfo() const {return tinfo_key;} /** Set some status_flags. */ const basic & setflag(unsigned f) const {flags |= f; return *this;} /** Clear some status_flags. */ const basic & clearflag(unsigned f) const {flags &= ~f; return *this;} protected: void ensure_if_modifiable() const; // member variables protected: tinfo_t tinfo_key; ///< type info mutable unsigned flags; ///< of type status_flags mutable long hashvalue=0; ///< hash value }; // global variables extern int max_recursion_level; // convenience type checker template functions /** Check if obj is a T, including base classes. */ template inline bool is_a(const basic &obj) { return dynamic_cast(&obj) != nullptr; } /** Check if obj is a T, not including base classes. */ template inline bool is_exactly_a(const basic & obj) { return obj.tinfo() == &T::tinfo_static; } } // namespace GiNaC #endif // ndef __GINAC_BASIC_H__ pynac-pynac-0.6.0/ginac/class_info.h000066400000000000000000000124621264176364700173360ustar00rootroot00000000000000/** @file class_info.h * * Helper templates to provide per-class information for class hierarchies. */ /* * GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __GINAC_CLASS_INFO_H__ #define __GINAC_CLASS_INFO_H__ #include // for size_t #include #include #include #include #include #include #include namespace GiNaC { // OPT is the class that stores the actual per-class data. It must provide // get_name(), get_parent_name() and get_id() members. template class class_info { public: class_info(OPT o) : options(std::move(o)), next(first), parent(nullptr) { first = this; parents_identified = false; } /** Get pointer to class_info of parent class (or NULL). */ class_info *get_parent() const { identify_parents(); return parent; } /** Find class_info by name. */ static const class_info *find(const std::string &class_name); /** Dump class hierarchy to std::cout. */ static void dump_hierarchy(bool verbose = false); OPT options; private: struct tree_node { tree_node(class_info *i) : info(i) {} void add_child(tree_node *n) { children.push_back(n); } std::vector children; class_info *info; }; static void dump_tree(tree_node *n, const std::string & prefix, bool verbose); static void identify_parents(); static class_info *first; class_info *next; mutable class_info *parent; static bool parents_identified; }; template const class_info *class_info::find(const std::string &class_name) { // Use a map for faster lookup. The registered_class_info list doesn't // change at run-time, so it's sufficient to construct the map once // on the first trip through this function. typedef std::map name_map_type; static name_map_type name_map; static bool name_map_initialized = false; if (!name_map_initialized) { // Construct map const class_info *p = first; while (p) { name_map[p->options.get_name()] = p; p = p->next; } name_map_initialized = true; } typename name_map_type::const_iterator it = name_map.find(class_name); if (it == name_map.end()) throw (std::runtime_error("class '" + class_name + "' not registered")); else return it->second; } template void class_info::dump_tree(tree_node *n, const std::string & prefix, bool verbose) { std::string name = n->info->options.get_name(); std::cout << name; if (verbose) std::cout << " [ID 0x" << std::hex << std::setw(8) << std::setfill('0') << n->info->options.get_id() << std::dec << "]" << std::endl; size_t num_children = n->children.size(); if (num_children) { for (size_t i = 0; i < num_children; ++i) { if (verbose) { std::cout << prefix << " +- "; if (i == num_children - 1) dump_tree(n->children[i], prefix + " ", verbose); else dump_tree(n->children[i], prefix + " | ", verbose); } else { std::string spaces(name.size(), ' '); if (i > 0) std::cout << prefix << spaces; if (num_children == 1) std::cout << " --- "; else if (i > 0) std::cout << " +- "; else std::cout << " -+- "; if (i == num_children - 1) dump_tree(n->children[i], prefix + spaces + " ", verbose); else dump_tree(n->children[i], prefix + spaces + " | ", verbose); } } } else if (!verbose) std::cout << std::endl; } template void class_info::dump_hierarchy(bool verbose) { identify_parents(); // Create tree nodes for all class_infos std::vector tree; for (class_info *p = first; p; p = p->next) tree.push_back(tree_node(p)); // Identify children for all nodes and find the root tree_node *root = NULL; for (const auto & elem : tree) { class_info *p = elem.info->get_parent(); if (p) { for (const auto & elem1 : tree) { if (elem1.info == p) { elem1.add_child(&elem); break; } } } else root = &elem; } // Print hierarchy tree starting at the root dump_tree(root, "", verbose); } template void class_info::identify_parents() { if (!parents_identified) { for (class_info *p = first; p; p = p->next) { const char *parent_name = p->options.get_parent_name(); for (class_info *q = first; q; q = q->next) { if (std::strcmp(q->options.get_name(), parent_name) == 0) { p->parent = q; break; } } } parents_identified = true; } } template class_info *class_info::first = nullptr; template bool class_info::parents_identified = false; } // namespace GiNaC #endif // ndef __GINAC_CLASS_INFO_H__ pynac-pynac-0.6.0/ginac/clifford.cpp000066400000000000000000001254751264176364700173520ustar00rootroot00000000000000/** @file clifford.cpp * * Implementation of GiNaC's clifford algebra (Dirac gamma) objects. */ /* * GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ex.h" #include "clifford.h" #include "idx.h" #include "ncmul.h" #include "symbol.h" #include "numeric.h" // for I #include "symmetry.h" #include "lst.h" #include "relational.h" #include "operators.h" #include "add.h" #include "mul.h" #include "power.h" #include "matrix.h" #include "archive.h" #include "utils.h" #include namespace GiNaC { GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(clifford, indexed, print_func(&clifford::do_print_dflt). print_func(&clifford::do_print_latex)) const tinfo_static_t clifford::return_type_tinfo_static[256] = {{}}; GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(diracone, tensor, print_func(&diracone::do_print). print_func(&diracone::do_print_latex)) GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(cliffordunit, tensor, print_func(&cliffordunit::do_print). print_func(&cliffordunit::do_print_latex)) GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(diracgamma, cliffordunit, print_func(&diracgamma::do_print). print_func(&diracgamma::do_print_latex)) GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(diracgamma5, tensor, print_func(&diracgamma5::do_print). print_func(&diracgamma5::do_print_latex)) GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(diracgammaL, tensor, print_func(&diracgammaL::do_print). print_func(&diracgammaL::do_print_latex)) GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(diracgammaR, tensor, print_func(&diracgammaR::do_print). print_func(&diracgammaR::do_print_latex)) ////////// // default constructors ////////// clifford::clifford() : representation_label(0), metric(0), commutator_sign(-1) { tinfo_key = &clifford::tinfo_static; } DEFAULT_CTOR(diracone) DEFAULT_CTOR(cliffordunit) DEFAULT_CTOR(diracgamma) DEFAULT_CTOR(diracgamma5) DEFAULT_CTOR(diracgammaL) DEFAULT_CTOR(diracgammaR) ////////// // other constructors ////////// /** Construct object without any indices. This constructor is for internal * use only. Use the dirac_ONE() function instead. * @see dirac_ONE */ clifford::clifford(const ex & b, unsigned char rl) : inherited(b), representation_label(rl), metric(0), commutator_sign(-1) { tinfo_key = &clifford::tinfo_static; } /** Construct object with one Lorentz index. This constructor is for internal * use only. Use the clifford_unit() or dirac_gamma() functions instead. * @see clifford_unit * @see dirac_gamma */ clifford::clifford(const ex & b, const ex & mu, ex metr, unsigned char rl, int comm_sign) : inherited(b, mu), representation_label(rl), metric(std::move(metr)), commutator_sign(comm_sign) { GINAC_ASSERT(is_a(mu)); tinfo_key = &clifford::tinfo_static; } clifford::clifford(unsigned char rl, ex metr, int comm_sign, const exvector & v, bool discardable) : inherited(not_symmetric(), v, discardable), representation_label(rl), metric(std::move(metr)), commutator_sign(comm_sign) { tinfo_key = &clifford::tinfo_static; } clifford::clifford(unsigned char rl, ex metr, int comm_sign, std::unique_ptr vp) : inherited(not_symmetric(), std::move(vp)), representation_label(rl), metric(std::move(metr)), commutator_sign(comm_sign) { tinfo_key = &clifford::tinfo_static; } ////////// // archiving ////////// clifford::clifford(const archive_node & n, lst & sym_lst) : inherited(n, sym_lst) { unsigned rl; n.find_unsigned("label", rl); representation_label = rl; n.find_ex("metric", metric, sym_lst); n.find_unsigned("commutator_sign+1", rl); commutator_sign = rl - 1; } void clifford::archive(archive_node & n) const { inherited::archive(n); n.add_unsigned("label", representation_label); n.add_ex("metric", metric); n.add_unsigned("commutator_sign+1", commutator_sign+1); } DEFAULT_UNARCHIVE(clifford) DEFAULT_ARCHIVING(diracone) DEFAULT_ARCHIVING(cliffordunit) DEFAULT_ARCHIVING(diracgamma) DEFAULT_ARCHIVING(diracgamma5) DEFAULT_ARCHIVING(diracgammaL) DEFAULT_ARCHIVING(diracgammaR) ex clifford::get_metric(const ex & i, const ex & j, bool symmetrised) const { if (is_a(metric)) { if (symmetrised && !(ex_to(ex_to(metric).get_symmetry()).has_symmetry())) { if (is_a(metric.op(0))) { return indexed((ex_to(metric.op(0)).add(ex_to(metric.op(0)).transpose())).mul(numeric(1, 2)), symmetric2(), i, j); } else { return simplify_indexed(indexed(metric.op(0)*_ex1_2, i, j) + indexed(metric.op(0)*_ex1_2, j, i)); } } else { return metric.subs(lst(metric.op(1) == i, metric.op(2) == j), subs_options::no_pattern); } } else { exvector indices = metric.get_free_indices(); if (symmetrised) return _ex1_2*simplify_indexed(metric.subs(lst(indices[0] == i, indices[1] == j), subs_options::no_pattern) + metric.subs(lst(indices[0] == j, indices[1] == i), subs_options::no_pattern)); else return metric.subs(lst(indices[0] == i, indices[1] == j), subs_options::no_pattern); } } bool clifford::same_metric(const ex & other) const { ex metr; if (is_a(other)) metr = ex_to(other).get_metric(); else metr = other; if (is_a(metr)) return metr.op(0).is_equal(get_metric().op(0)); else { exvector indices = metr.get_free_indices(); return (indices.size() == 2) && simplify_indexed(get_metric(indices[0], indices[1])-metr).is_zero(); } } ////////// // functions overriding virtual functions from base classes ////////// ex clifford::op(size_t i) const { GINAC_ASSERT(i(subsed)) { ex prevmetric = ex_to(subsed).metric; ex newmetric = prevmetric.subs(m, options); if(!are_ex_trivially_equal(prevmetric, newmetric)) { clifford c = ex_to(subsed); c.metric = newmetric; subsed = c; } } return subsed; } int clifford::compare_same_type(const basic & other) const { GINAC_ASSERT(is_a(other)); const clifford &o = static_cast(other); if (representation_label != o.representation_label) { // different representation label return representation_label < o.representation_label ? -1 : 1; } return inherited::compare_same_type(other); } bool clifford::match_same_type(const basic & other) const { GINAC_ASSERT(is_a(other)); const clifford &o = static_cast(other); return ((representation_label == o.representation_label) && (commutator_sign == o.get_commutator_sign()) && same_metric(o)); } static bool is_dirac_slash(const ex & seq0) { return !is_a(seq0) && !is_a(seq0) && !is_a(seq0) && !is_a(seq0) && !is_a(seq0); } void clifford::do_print_dflt(const print_dflt & c, unsigned level) const { // dirac_slash() object is printed differently if (is_dirac_slash(seq[0])) { seq[0].print(c, precedence()); c.s << "\\"; } else { // We do not print representation label if it is 0 if (representation_label == 0) { this->print_dispatch(c, level); } else { // otherwise we put it before indices in square brackets; the code is borrowed from indexed.cpp if (precedence() <= level) { c.s << '('; } seq[0].print(c, precedence()); c.s << '[' << int(representation_label) << ']'; printindices(c, level); if (precedence() <= level) { c.s << ')'; } } } } void clifford::do_print_latex(const print_latex & c, unsigned level) const { // dirac_slash() object is printed differently if (is_dirac_slash(seq[0])) { c.s << "{"; seq[0].print(c, precedence()); c.s << "\\hspace{-1.0ex}/}"; } else { c.s << "\\clifford[" << int(representation_label) << "]"; this->print_dispatch(c, level); } } DEFAULT_COMPARE(diracone) DEFAULT_COMPARE(cliffordunit) DEFAULT_COMPARE(diracgamma) DEFAULT_COMPARE(diracgamma5) DEFAULT_COMPARE(diracgammaL) DEFAULT_COMPARE(diracgammaR) DEFAULT_PRINT_LATEX(diracone, "ONE", "\\mathbf{1}") DEFAULT_PRINT_LATEX(cliffordunit, "e", "e") DEFAULT_PRINT_LATEX(diracgamma, "gamma", "\\gamma") DEFAULT_PRINT_LATEX(diracgamma5, "gamma5", "{\\gamma^5}") DEFAULT_PRINT_LATEX(diracgammaL, "gammaL", "{\\gamma_L}") DEFAULT_PRINT_LATEX(diracgammaR, "gammaR", "{\\gamma_R}") /** This function decomposes gamma~mu -> (1, mu) and a\ -> (a.ix, ix) */ static void base_and_index(const ex & c, ex & b, ex & i) { GINAC_ASSERT(is_a(c)); GINAC_ASSERT(c.nops() == 2+1); if (is_a(c.op(0))) { // proper dirac gamma object or clifford unit i = c.op(1); b = _ex1; } else if (is_a(c.op(0)) || is_a(c.op(0)) || is_a(c.op(0))) { // gamma5/L/R i = _ex0; b = _ex1; } else { // slash object, generate new dummy index varidx ix((new symbol)->setflag(status_flags::dynallocated), ex_to(c.op(1)).get_dim()); b = indexed(c.op(0), ix.toggle_variance()); i = ix; } } /** Predicate for finding non-clifford objects. */ struct is_not_a_clifford : public std::unary_function { bool operator()(const ex & e) { return !is_a(e); } }; /** Contraction of a gamma matrix with something else. */ bool diracgamma::contract_with(exvector::iterator self, exvector::iterator other, exvector &) const { GINAC_ASSERT(is_a(*self)); GINAC_ASSERT(is_a(*other)); GINAC_ASSERT(is_a(self->op(0))); unsigned char rl = ex_to(*self).get_representation_label(); ex dim = ex_to(self->op(1)).get_dim(); if (other->nops() > 1) dim = minimal_dim(dim, ex_to(other->op(1)).get_dim()); if (is_a(*other)) { // Contraction only makes sense if the represenation labels are equal if (ex_to(*other).get_representation_label() != rl) return false; size_t num = other - self; // gamma~mu gamma.mu = dim ONE if (num == 1) { *self = dim; *other = dirac_ONE(rl); return true; // gamma~mu gamma~alpha gamma.mu = (2-dim) gamma~alpha } else if (num == 2 && is_a(self[1])) { *self = 2 - dim; *other = _ex1; return true; // gamma~mu gamma~alpha gamma~beta gamma.mu = 4 g~alpha~beta + (dim-4) gamam~alpha gamma~beta } else if (num == 3 && is_a(self[1]) && is_a(self[2])) { ex b1, i1, b2, i2; base_and_index(self[1], b1, i1); base_and_index(self[2], b2, i2); *self = 4 * lorentz_g(i1, i2) * b1 * b2 * dirac_ONE(rl) + (dim - 4) * self[1] * self[2]; self[1] = _ex1; self[2] = _ex1; *other = _ex1; return true; // gamma~mu gamma~alpha gamma~beta gamma~delta gamma.mu = -2 gamma~delta gamma~beta gamma~alpha - (dim-4) gamam~alpha gamma~beta gamma~delta } else if (num == 4 && is_a(self[1]) && is_a(self[2]) && is_a(self[3])) { *self = -2 * self[3] * self[2] * self[1] - (dim - 4) * self[1] * self[2] * self[3]; self[1] = _ex1; self[2] = _ex1; self[3] = _ex1; *other = _ex1; return true; // gamma~mu Sodd gamma.mu = -2 Sodd_R // (Chisholm identity in 4 dimensions) } else if (!((other - self) & 1) && dim.is_equal(4)) { if (std::find_if(self + 1, other, is_not_a_clifford()) != other) return false; *self = ncmul(exvector(std::reverse_iterator(other), std::reverse_iterator(self + 1)), true); std::fill(self + 1, other, _ex1); *other = _ex_2; return true; // gamma~mu Sodd gamma~alpha gamma.mu = 2 gamma~alpha Sodd + 2 Sodd_R gamma~alpha // (commutate contracted indices towards each other, then use // Chisholm identity in 4 dimensions) } else if (((other - self) & 1) && dim.is_equal(4)) { if (std::find_if(self + 1, other, is_not_a_clifford()) != other) return false; auto next_to_last = other - 1; ex S = ncmul(exvector(self + 1, next_to_last), true); ex SR = ncmul(exvector(std::reverse_iterator(next_to_last), std::reverse_iterator(self + 1)), true); *self = (*next_to_last) * S + SR * (*next_to_last); std::fill(self + 1, other, _ex1); *other = _ex2; return true; // gamma~mu S gamma~alpha gamma.mu = 2 gamma~alpha S - gamma~mu S gamma.mu gamma~alpha // (commutate contracted indices towards each other, simplify_indexed() // will re-expand and re-run the simplification) } else { if (std::find_if(self + 1, other, is_not_a_clifford()) != other) return false; auto next_to_last = other - 1; ex S = ncmul(exvector(self + 1, next_to_last), true); *self = 2 * (*next_to_last) * S - (*self) * S * (*other) * (*next_to_last); std::fill(self + 1, other + 1, _ex1); return true; } } else if (is_a(other->op(0)) && other->nops() == 2) { // x.mu gamma~mu -> x-slash *self = dirac_slash(other->op(0), dim, rl); *other = _ex1; return true; } return false; } /** Contraction of a Clifford unit with something else. */ bool cliffordunit::contract_with(exvector::iterator self, exvector::iterator other, exvector &) const { GINAC_ASSERT(is_a(*self)); GINAC_ASSERT(is_a(*other)); GINAC_ASSERT(is_a(self->op(0))); clifford unit = ex_to(*self); unsigned char rl = unit.get_representation_label(); if (is_a(*other)) { // Contraction only makes sense if the represenation labels are equal // and the metrics are the same if ((ex_to(*other).get_representation_label() != rl) && unit.same_metric(*other)) return false; auto before_other = other - 1; ex mu = self->op(1); ex mu_toggle = other->op(1); ex alpha = before_other->op(1); // e~mu e.mu = Tr ONE if (other - self == 1) { *self = unit.get_metric(mu, mu_toggle, true); *other = dirac_ONE(rl); return true; } else if (other - self == 2) { if (is_a(*before_other) && ex_to(*before_other).get_representation_label() == rl) { // e~mu e~alpha e.mu = 2*e~mu B(alpha, mu.toggle_variance())-Tr(B) e~alpha *self = 2 * (*self) * unit.get_metric(alpha, mu_toggle, true) - unit.get_metric(mu, mu_toggle, true) * (*before_other); *before_other = _ex1; *other = _ex1; return true; } else { // e~mu S e.mu = Tr S ONE *self = unit.get_metric(mu, mu_toggle, true); *other = dirac_ONE(rl); return true; } } else { // e~mu S e~alpha e.mu = 2 e~mu S B(alpha, mu.toggle_variance()) - e~mu S e.mu e~alpha // (commutate contracted indices towards each other, simplify_indexed() // will re-expand and re-run the simplification) if (std::find_if(self + 1, other, is_not_a_clifford()) != other) { return false; } ex S = ncmul(exvector(self + 1, before_other), true); if (is_a(*before_other) && ex_to(*before_other).get_representation_label() == rl) { *self = 2 * (*self) * S * unit.get_metric(alpha, mu_toggle, true) - (*self) * S * (*other) * (*before_other); } else { // simply commutes *self = (*self) * S * (*other) * (*before_other); } std::fill(self + 1, other + 1, _ex1); return true; } } return false; } /** Perform automatic simplification on noncommutative product of clifford * objects. This removes superfluous ONEs, permutes gamma5/L/R's to the front * and removes squares of gamma objects. */ ex clifford::eval_ncmul(const exvector & v) const { exvector s; s.reserve(v.size()); // Remove superfluous ONEs auto cit = v.begin(), citend = v.end(); while (cit != citend) { if (!is_a(*cit) || !is_a(cit->op(0))) s.push_back(*cit); cit++; } bool something_changed = false; int sign = 1; // Anticommutate gamma5/L/R's to the front if (s.size() >= 2) { auto first = s.begin(), next_to_last = s.end() - 2; while (true) { auto it = next_to_last; while (true) { auto it2 = it + 1; if (is_a(*it) && is_a(*it2)) { ex e1 = it->op(0), e2 = it2->op(0); if (is_a(e2)) { if (is_a(e1) || is_a(e1)) { // gammaL/R gamma5 -> gamma5 gammaL/R it->swap(*it2); something_changed = true; } else if (!is_a(e1)) { // gamma5 gamma5 -> gamma5 gamma5 (do nothing) // x gamma5 -> -gamma5 x it->swap(*it2); sign = -sign; something_changed = true; } } else if (is_a(e2)) { if (is_a(e1)) { // gammaR gammaL -> 0 return _ex0; } else if (!is_a(e1) && !is_a(e1)) { // gammaL gammaL -> gammaL gammaL (do nothing) // gamma5 gammaL -> gamma5 gammaL (do nothing) // x gammaL -> gammaR x it->swap(*it2); *it = clifford(diracgammaR(), ex_to(*it).get_representation_label()); something_changed = true; } } else if (is_a(e2)) { if (is_a(e1)) { // gammaL gammaR -> 0 return _ex0; } else if (!is_a(e1) && !is_a(e1)) { // gammaR gammaR -> gammaR gammaR (do nothing) // gamma5 gammaR -> gamma5 gammaR (do nothing) // x gammaR -> gammaL x it->swap(*it2); *it = clifford(diracgammaL(), ex_to(*it).get_representation_label()); something_changed = true; } } } if (it == first) break; --it; } if (next_to_last == first) break; --next_to_last; } } // Remove equal adjacent gammas if (s.size() >= 2) { exvector::iterator it, itend = s.end() - 1; for (it = s.begin(); it != itend; ++it) { ex & a = it[0]; ex & b = it[1]; if (!is_a(a) || !is_a(b)) continue; const ex & ag = a.op(0); const ex & bg = b.op(0); bool a_is_cliffordunit = is_a(ag); bool b_is_cliffordunit = is_a(bg); if (a_is_cliffordunit && b_is_cliffordunit && ex_to(a).same_metric(b) && (ex_to(a).get_commutator_sign() == -1)) { // This is done only for Clifford algebras const ex & ia = a.op(1); const ex & ib = b.op(1); if (ia.is_equal(ib)) { // gamma~alpha gamma~alpha -> g~alpha~alpha a = ex_to(a).get_metric(ia, ib, true); b = dirac_ONE(representation_label); something_changed = true; } } else if ((is_a(ag) && is_a(bg))) { // Remove squares of gamma5 a = dirac_ONE(representation_label); b = dirac_ONE(representation_label); something_changed = true; } else if ((is_a(ag) && is_a(bg)) || (is_a(ag) && is_a(bg))) { // Remove squares of gammaL/R b = dirac_ONE(representation_label); something_changed = true; } else if (is_a(ag) && is_a(bg)) { // gammaL and gammaR are orthogonal return _ex0; } else if (is_a(ag) && is_a(bg)) { // gamma5 gammaL -> -gammaL a = dirac_ONE(representation_label); sign = -sign; something_changed = true; } else if (is_a(ag) && is_a(bg)) { // gamma5 gammaR -> gammaR a = dirac_ONE(representation_label); something_changed = true; } else if (!a_is_cliffordunit && !b_is_cliffordunit && ag.is_equal(bg)) { // a\ a\ -> a^2 varidx ix((new symbol)->setflag(status_flags::dynallocated), ex_to(a.op(1)).minimal_dim(ex_to(b.op(1)))); a = indexed(ag, ix) * indexed(ag, ix.toggle_variance()); b = dirac_ONE(representation_label); something_changed = true; } } } if (s.empty()) return dirac_ONE(representation_label) * sign; if (something_changed) return reeval_ncmul(s) * sign; else return hold_ncmul(s) * sign; } ex clifford::thiscontainer(const exvector & v) const { return clifford(representation_label, metric, commutator_sign, v); } ex clifford::thiscontainer(std::unique_ptr vp) const { return clifford(representation_label, metric, commutator_sign, std::move(vp)); } ex diracgamma5::conjugate() const { return _ex_1 * (*this); } ex diracgammaL::conjugate() const { return (new diracgammaR)->setflag(status_flags::dynallocated); } ex diracgammaR::conjugate() const { return (new diracgammaL)->setflag(status_flags::dynallocated); } ////////// // global functions ////////// ex dirac_ONE(unsigned char rl) { static ex ONE = (new diracone)->setflag(status_flags::dynallocated); return clifford(ONE, rl); } ex clifford_unit(const ex & mu, const ex & metr, unsigned char rl) { static ex unit = (new cliffordunit)->setflag(status_flags::dynallocated); if (!is_a(mu)) throw(std::invalid_argument("clifford_unit(): index of Clifford unit must be of type idx or varidx")); exvector indices = metr.get_free_indices(); if (indices.size() == 2) { return clifford(unit, mu, metr, rl); } else if (is_a(metr)) { matrix M = ex_to(metr); unsigned n = M.rows(); bool symmetric = true; static idx xi((new symbol)->setflag(status_flags::dynallocated), n), chi((new symbol)->setflag(status_flags::dynallocated), n); if ((n == M.cols()) && (n == ex_to(mu).get_dim())) { for (unsigned i = 0; i < n; i++) { for (unsigned j = i+1; j < n; j++) { if (M(i, j) != M(j, i)) { symmetric = false; } } } return clifford(unit, mu, indexed(metr, symmetric?symmetric2():not_symmetric(), xi, chi), rl); } else { throw(std::invalid_argument("clifford_unit(): metric for Clifford unit must be a square matrix with the same dimensions as index")); } } else if (indices.size() == 0) { // a tensor or other expression without indices static varidx xi((new symbol)->setflag(status_flags::dynallocated), ex_to(mu).get_dim()), chi((new symbol)->setflag(status_flags::dynallocated), ex_to(mu).get_dim()); return clifford(unit, mu, indexed(metr, xi, chi), rl); } else throw(std::invalid_argument("clifford_unit(): metric for Clifford unit must be of type tensor, matrix or an expression with two free indices")); } ex dirac_gamma(const ex & mu, unsigned char rl) { static ex gamma = (new diracgamma)->setflag(status_flags::dynallocated); if (!is_a(mu)) throw(std::invalid_argument("dirac_gamma(): index of Dirac gamma must be of type varidx")); static varidx xi((new symbol)->setflag(status_flags::dynallocated), ex_to(mu).get_dim()), chi((new symbol)->setflag(status_flags::dynallocated), ex_to(mu).get_dim()); return clifford(gamma, mu, indexed((new minkmetric)->setflag(status_flags::dynallocated), symmetric2(), xi, chi), rl); } ex dirac_gamma5(unsigned char rl) { static ex gamma5 = (new diracgamma5)->setflag(status_flags::dynallocated); return clifford(gamma5, rl); } ex dirac_gammaL(unsigned char rl) { static ex gammaL = (new diracgammaL)->setflag(status_flags::dynallocated); return clifford(gammaL, rl); } ex dirac_gammaR(unsigned char rl) { static ex gammaR = (new diracgammaR)->setflag(status_flags::dynallocated); return clifford(gammaR, rl); } ex dirac_slash(const ex & e, const ex & dim, unsigned char rl) { // Slashed vectors are actually stored as a clifford object with the // vector as its base expression and a (dummy) index that just serves // for storing the space dimensionality static varidx xi((new symbol)->setflag(status_flags::dynallocated), dim), chi((new symbol)->setflag(status_flags::dynallocated), dim); return clifford(e, varidx(0, dim), indexed((new minkmetric)->setflag(status_flags::dynallocated), symmetric2(), xi, chi), rl); } /** Check whether a given tinfo key (as returned by return_type_tinfo() * is that of a clifford object (with an arbitrary representation label). */ bool is_clifford_tinfo(tinfo_t ti) { p_int start_loc=(p_int)&clifford::return_type_tinfo_static; return (p_int)ti>=start_loc && (p_int)ti & rls, const ex & trONE) { if (is_a(e)) { unsigned char rl = ex_to(e).get_representation_label(); // Are we taking the trace over this object's representation label? if (rls.find(rl) == rls.end()) return e; // Yes, all elements are traceless, except for dirac_ONE and dirac_L/R const ex & g = e.op(0); if (is_a(g)) return trONE; else if (is_a(g) || is_a(g)) return trONE/2; else return _ex0; } else if (is_exactly_a(e)) { // Trace of product: pull out non-clifford factors ex prod = _ex1; for (size_t i=0; i(e)) { unsigned char rl = get_representation_label(e.return_type_tinfo()); // Are we taking the trace over this string's representation label? if (rls.find(rl) == rls.end()) return e; // Substitute gammaL/R and expand product, if necessary ex e_expanded = e.subs(lst( dirac_gammaL(rl) == (dirac_ONE(rl)-dirac_gamma5(rl))/2, dirac_gammaR(rl) == (dirac_ONE(rl)+dirac_gamma5(rl))/2 ), subs_options::no_pattern).expand(); if (!is_a(e_expanded)) return dirac_trace(e_expanded, rls, trONE); // gamma5 gets moved to the front so this check is enough bool has_gamma5 = is_a(e.op(0).op(0)); size_t num = e.nops(); if (has_gamma5) { // Trace of gamma5 * odd number of gammas and trace of // gamma5 * gamma.mu * gamma.nu are zero if ((num & 1) == 0 || num == 3) return _ex0; // Tr gamma5 gamma.mu gamma.nu gamma.rho gamma.sigma = 4I * epsilon(mu, nu, rho, sigma) // (the epsilon is always 4-dimensional) if (num == 5) { ex b1, i1, b2, i2, b3, i3, b4, i4; base_and_index(e.op(1), b1, i1); base_and_index(e.op(2), b2, i2); base_and_index(e.op(3), b3, i3); base_and_index(e.op(4), b4, i4); return trONE * I * (lorentz_eps(ex_to(i1).replace_dim(_ex4), ex_to(i2).replace_dim(_ex4), ex_to(i3).replace_dim(_ex4), ex_to(i4).replace_dim(_ex4)) * b1 * b2 * b3 * b4).simplify_indexed(); } // Tr gamma5 S_2k = // I/4! * epsilon0123.mu1.mu2.mu3.mu4 * Tr gamma.mu1 gamma.mu2 gamma.mu3 gamma.mu4 S_2k // (the epsilon is always 4-dimensional) exvector ix(num-1), bv(num-1); for (size_t i=1; i(idx1).replace_dim(_ex4), ex_to(idx2).replace_dim(_ex4), ex_to(idx3).replace_dim(_ex4), ex_to(idx4).replace_dim(_ex4)) * trace_string(v.begin(), num - 4); } } } } delete[] iv; return trONE * I * result * mul(bv); } else { // no gamma5 // Trace of odd number of gammas is zero if ((num & 1) == 1) return _ex0; // Tr gamma.mu gamma.nu = 4 g.mu.nu if (num == 2) { ex b1, i1, b2, i2; base_and_index(e.op(0), b1, i1); base_and_index(e.op(1), b2, i2); return trONE * (lorentz_g(i1, i2) * b1 * b2).simplify_indexed(); } exvector iv(num), bv(num); for (size_t i=0; i 0) { // Trace maps to all other container classes (this includes sums) pointer_to_map_function_2args &, const ex &> fcn(dirac_trace, rls, trONE); return e.map(fcn); } else return _ex0; } ex dirac_trace(const ex & e, const lst & rll, const ex & trONE) { // Convert list to set std::set rls; for (const auto & elem : rll) { if (elem.info(info_flags::nonnegint)) rls.insert(ex_to(elem).to_int()); } return dirac_trace(e, rls, trONE); } ex dirac_trace(const ex & e, unsigned char rl, const ex & trONE) { // Convert label to set std::set rls; rls.insert(rl); return dirac_trace(e, rls, trONE); } ex canonicalize_clifford(const ex & e_) { pointer_to_map_function fcn(canonicalize_clifford); if (is_a(e_) // || is_a(e) || is_a(e) || e_.info(info_flags::list)) { return e_.map(fcn); } else { ex e=simplify_indexed(e_); // Scan for any ncmul objects exmap srl; ex aux = e.to_rational(srl); for (auto & elem : srl) { ex lhs = elem.first; ex rhs = elem.second; if (is_exactly_a(rhs) && rhs.return_type() == return_types::noncommutative && is_clifford_tinfo(rhs.return_type_tinfo())) { // Expand product, if necessary ex rhs_expanded = rhs.expand(); if (!is_a(rhs_expanded)) { elem.second = canonicalize_clifford(rhs_expanded); continue; } else if (!is_a(rhs.op(0))) continue; exvector v; v.reserve(rhs.nops()); for (size_t j=0; j(it->op(0)) || is_a(it->op(0)) || is_a(it->op(0))) ++it; while (it != next_to_last) { if (it[0].compare(it[1]) > 0) { ex save0 = it[0], save1 = it[1]; ex b1, i1, b2, i2; base_and_index(it[0], b1, i1); base_and_index(it[1], b2, i2); // for Clifford algebras (commutator_sign == -1) metric should be symmetrised it[0] = (ex_to(save0).get_metric(i1, i2, ex_to(save0).get_commutator_sign() == -1) * b1 * b2).simplify_indexed(); it[1] = v.size() ? _ex2 * dirac_ONE(ex_to(save0).get_representation_label()) : _ex2; ex sum = ncmul(v); it[0] = save1; it[1] = save0; sum += ex_to(save0).get_commutator_sign() * ncmul(v, true); elem.second = canonicalize_clifford(sum); goto next_sym; } ++it; } next_sym: ; } } return aux.subs(srl, subs_options::no_pattern).simplify_indexed(); } } ex clifford_prime(const ex & e) { pointer_to_map_function fcn(clifford_prime); if (is_a(e) && is_a(e.op(0))) { return -e; } else if (is_a(e) || is_a(e) || is_a(e) //|| is_a(e) || is_a(e) || is_a(e) || e.info(info_flags::list)) { return e.map(fcn); } else if (is_a(e)) { return pow(clifford_prime(e.op(0)), e.op(1)); } else return e; } ex remove_dirac_ONE(const ex & e, unsigned char rl, unsigned options) { pointer_to_map_function_2args fcn(remove_dirac_ONE, rl, options | 1); bool need_reevaluation = false; ex e1 = e; if (! (options & 1) ) { // is not a child if (options & 2) e1 = expand_dummy_sum(e, true); e1 = canonicalize_clifford(e1); } if (is_a(e1) && ex_to(e1).get_representation_label() >= rl) { if (is_a(e1.op(0))) return 1; else throw(std::invalid_argument("remove_dirac_ONE(): expression is a non-scalar Clifford number!")); } else if (is_a(e1) || is_a(e1) || is_a(e1) || is_a(e1) || e1.info(info_flags::list)) { if (options & 3) // is a child or was already expanded return e1.map(fcn); else try { return e1.map(fcn); } catch (std::exception &p) { need_reevaluation = true; } } else if (is_a(e1)) { if (options & 3) // is a child or was already expanded return pow(remove_dirac_ONE(e1.op(0), rl, options | 1), e1.op(1)); else try { return pow(remove_dirac_ONE(e1.op(0), rl, options | 1), e1.op(1)); } catch (std::exception &p) { need_reevaluation = true; } } if (need_reevaluation) return remove_dirac_ONE(e, rl, options | 2); return e1; } int clifford_max_label(const ex & e, bool ignore_ONE) { if (is_a(e)) if (ignore_ONE && is_a(e.op(0))) return -1; else return ex_to(e).get_representation_label(); else { int rl = -1; for (size_t i=0; i < e.nops(); i++) rl = (rl > clifford_max_label(e.op(i), ignore_ONE)) ? rl : clifford_max_label(e.op(i), ignore_ONE); return rl; } } ex clifford_norm(const ex & e) { return sqrt(remove_dirac_ONE(e * clifford_bar(e))); } ex clifford_inverse(const ex & e) { ex norm = clifford_norm(e); if (!norm.is_zero()) return clifford_bar(e) / pow(norm, 2); else throw(std::invalid_argument("clifford_inverse(): cannot find inverse of Clifford number with zero norm!")); } ex lst_to_clifford(const ex & v, const ex & mu, const ex & metr, unsigned char rl) { if (!ex_to(mu).is_dim_numeric()) throw(std::invalid_argument("lst_to_clifford(): Index should have a numeric dimension")); ex e = clifford_unit(mu, metr, rl); return lst_to_clifford(v, e); } ex lst_to_clifford(const ex & v, const ex & e) { unsigned min, max; if (is_a(e)) { ex mu = e.op(1); ex mu_toggle = is_a(mu) ? ex_to(mu).toggle_variance() : mu; unsigned dim = (ex_to(ex_to(mu).get_dim())).to_int(); if (is_a(v)) { if (ex_to(v).cols() > ex_to(v).rows()) { min = ex_to(v).rows(); max = ex_to(v).cols(); } else { min = ex_to(v).cols(); max = ex_to(v).rows(); } if (min == 1) { if (dim == max) return indexed(v, mu_toggle) * e; else if (max - dim == 1) { if (ex_to(v).cols() > ex_to(v).rows()) return v.op(0) * dirac_ONE(ex_to(e).get_representation_label()) + indexed(sub_matrix(ex_to(v), 0, 1, 1, dim), mu_toggle) * e; else return v.op(0) * dirac_ONE(ex_to(e).get_representation_label()) + indexed(sub_matrix(ex_to(v), 1, dim, 0, 1), mu_toggle) * e; } else throw(std::invalid_argument("lst_to_clifford(): dimensions of vector and clifford unit mismatch")); } else throw(std::invalid_argument("lst_to_clifford(): first argument should be a vector (nx1 or 1xn matrix)")); } else if (v.info(info_flags::list)) { if (dim == ex_to(v).nops()) return indexed(matrix(dim, 1, ex_to(v)), mu_toggle) * e; else if (ex_to(v).nops() - dim == 1) return v.op(0) * dirac_ONE(ex_to(e).get_representation_label()) + indexed(sub_matrix(matrix(dim+1, 1, ex_to(v)), 1, dim, 0, 1), mu_toggle) * e; else throw(std::invalid_argument("lst_to_clifford(): list length and dimension of clifford unit mismatch")); } else throw(std::invalid_argument("lst_to_clifford(): cannot construct from anything but list or vector")); } else throw(std::invalid_argument("lst_to_clifford(): the second argument should be a Clifford unit")); } /** Auxiliary structure to define a function for striping one Clifford unit * from vectors. Used in clifford_to_lst(). */ static ex get_clifford_comp(const ex & e, const ex & c) { pointer_to_map_function_1arg fcn(get_clifford_comp, c); int ival = ex_to(ex_to(c.op(1)).get_value()).to_int(); if (is_a(e) || e.info(info_flags::list) // || is_a(e) || is_a(e) || is_a(e)) return e.map(fcn); else if (is_a(e) || is_a(e)) { // find a Clifford unit with the same metric, delete it and substitute its index size_t ind = e.nops() + 1; for (size_t j = 0; j < e.nops(); j++) { if (is_a(e.op(j)) && ex_to(c).same_metric(e.op(j))) { if (ind > e.nops()) ind = j; else throw(std::invalid_argument("get_clifford_comp(): expression is a Clifford multi-vector")); } } if (ind < e.nops()) { ex S = 1; bool same_value_index, found_dummy; same_value_index = ( ex_to(e.op(ind).op(1)).is_numeric() && (ival == ex_to(ex_to(e.op(ind).op(1)).get_value()).to_int()) ); found_dummy = same_value_index; for(size_t j=0; j < e.nops(); j++) { if (j != ind) { if (same_value_index) S = S * e.op(j); else { exvector ind_vec = ex_to(e.op(j)).get_dummy_indices(ex_to(e.op(ind))); if (ind_vec.size() > 0) { found_dummy = true; exvector::const_iterator it = ind_vec.begin(), itend = ind_vec.end(); while (it != itend) { ex curridx = *it; ex curridx_toggle = is_a(curridx) ? ex_to(curridx).toggle_variance() : curridx; S = S * e.op(j).subs(lst(curridx == ival, curridx_toggle == ival), subs_options::no_pattern); ++it; } } else S = S * e.op(j); } } return (found_dummy ? S : 0); } } else throw(std::invalid_argument("get_clifford_comp(): expression is not a Clifford vector to the given units")); } else if (e.is_zero()) return e; else { if (is_a(e) and ex_to(e).same_metric(c) and ex_to(e.op(1)).is_numeric() and (ival != ex_to(ex_to(e.op(1)).get_value()).to_int()) ) return 0; else return 1; } throw(std::invalid_argument("get_clifford_comp(): expression is not usable as a Clifford vector")); } lst clifford_to_lst(const ex & e, const ex & c, bool algebraic) { GINAC_ASSERT(is_a(c)); ex mu = c.op(1); if (! ex_to(mu).is_dim_numeric()) throw(std::invalid_argument("clifford_to_lst(): index should have a numeric dimension")); unsigned int D = ex_to(ex_to(mu).get_dim()).to_int(); if (algebraic) // check if algebraic method is applicable for (unsigned int i = 0; i < D; i++) if (pow(c.subs(mu == i, subs_options::no_pattern), 2).is_zero() || (! is_a(pow(c.subs(mu == i, subs_options::no_pattern), 2)))) algebraic = false; lst V; ex v0 = remove_dirac_ONE(canonicalize_clifford(e+clifford_prime(e)).normal())/2; if (! v0.is_zero()) V.append(v0); ex e1 = canonicalize_clifford(e - v0 * dirac_ONE(ex_to(c).get_representation_label())); if (algebraic) { for (unsigned int i = 0; i < D; i++) V.append(remove_dirac_ONE( simplify_indexed(canonicalize_clifford(e1 * c.subs(mu == i, subs_options::no_pattern) + c.subs(mu == i, subs_options::no_pattern) * e1)) / (2*pow(c.subs(mu == i, subs_options::no_pattern), 2)))); } else { try { for (unsigned int i = 0; i < D; i++) V.append(get_clifford_comp(e1, c.subs(c.op(1) == i, subs_options::no_pattern))); } catch (std::exception &p) { /* Try to expand dummy summations to simplify the expression*/ e1 = canonicalize_clifford(expand_dummy_sum(e, true)); V.remove_all(); v0 = remove_dirac_ONE(canonicalize_clifford(e1+clifford_prime(e1)).normal())/2; if (! v0.is_zero()) { V.append(v0); e1 = canonicalize_clifford(e1 - v0 * dirac_ONE(ex_to(c).get_representation_label())); } for (unsigned int i = 0; i < D; i++) V.append(get_clifford_comp(e1, c.subs(c.op(1) == i, subs_options::no_pattern))); } } return V; } ex clifford_moebius_map(const ex & a, const ex & b, const ex & c, const ex & d, const ex & v, const ex & G, unsigned char rl) { ex x, D, cu; if (! is_a(v) && ! v.info(info_flags::list)) throw(std::invalid_argument("clifford_moebius_map(): parameter v should be either vector or list")); if (is_a(G)) { cu = G; } else { if (is_a(G)) { D = ex_to(G.op(1)).get_dim(); varidx mu((new symbol)->setflag(status_flags::dynallocated), D); cu = clifford_unit(mu, G, rl); } else if (is_a(G)) { D = ex_to(G).rows(); idx mu((new symbol)->setflag(status_flags::dynallocated), D); cu = clifford_unit(mu, G, rl); } else throw(std::invalid_argument("clifford_moebius_map(): metric should be an indexed object, matrix, or a Clifford unit")); } x = lst_to_clifford(v, cu); ex e = clifford_to_lst(simplify_indexed(canonicalize_clifford((a * x + b) * clifford_inverse(c * x + d))), cu, false); return (is_a(v) ? matrix(ex_to(v).rows(), ex_to(v).cols(), ex_to(e)) : e); } ex clifford_moebius_map(const ex & M, const ex & v, const ex & G, unsigned char rl) { if (is_a(M) && (ex_to(M).rows() == 2) && (ex_to(M).cols() == 2)) return clifford_moebius_map(M.op(0), M.op(1), M.op(2), M.op(3), v, G, rl); else throw(std::invalid_argument("clifford_moebius_map(): parameter M should be a 2x2 matrix")); } } // namespace GiNaC pynac-pynac-0.6.0/ginac/clifford.h000066400000000000000000000340061264176364700170040ustar00rootroot00000000000000/** @file clifford.h * * Interface to GiNaC's clifford algebra (Dirac gamma) objects. */ /* * GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __GINAC_CLIFFORD_H__ #define __GINAC_CLIFFORD_H__ #include "symbol.h" #include "indexed.h" #include "tensor.h" #include "idx.h" #include namespace GiNaC { /** This class holds an object representing an element of the Clifford * algebra (the Dirac gamma matrices). These objects only carry Lorentz * indices. Spinor indices are hidden. A representation label (an unsigned * 8-bit integer) is used to distinguish elements from different Clifford * algebras (objects with different labels commutate). */ class clifford : public indexed { GINAC_DECLARE_REGISTERED_CLASS(clifford, indexed) public: static const tinfo_static_t return_type_tinfo_static[256]; // other constructors public: clifford(const ex & b, unsigned char rl = 0); clifford(const ex & b, const ex & mu, ex metr, unsigned char rl = 0, int comm_sign = -1); // internal constructors clifford(unsigned char rl, ex metr, int comm_sign, const exvector & v, bool discardable = false); clifford(unsigned char rl, ex metr, int comm_sign, std::unique_ptr vp); // functions overriding virtual functions from base classes public: unsigned precedence() const override { return 65; } protected: ex eval_ncmul(const exvector & v) const override; bool match_same_type(const basic & other) const override; ex thiscontainer(const exvector & v) const override; ex thiscontainer(std::unique_ptr vp) const override; unsigned return_type() const override { return return_types::noncommutative; } tinfo_t return_type_tinfo() const override { return clifford::return_type_tinfo_static+representation_label; } // non-virtual functions in this class public: unsigned char get_representation_label() const { return representation_label; } ex get_metric() const { return metric; } virtual ex get_metric(const ex & i, const ex & j, bool symmetrised = false) const; bool same_metric(const ex & other) const; int get_commutator_sign() const { return commutator_sign; } //**< See the member variable commutator_sign */ inline size_t nops() const override {return inherited::nops() + 1; } ex op(size_t i) const override; ex & let_op(size_t i) override; ex subs(const exmap & m, unsigned options = 0) const override; protected: void do_print_dflt(const print_dflt & c, unsigned level) const; void do_print_latex(const print_latex & c, unsigned level) const; // member variables protected: unsigned char representation_label; /**< Representation label to distinguish independent spin lines */ ex metric; /**< Metric of the space, all constructors make it an indexed object */ int commutator_sign; /**< It is the sign in the definition e~i e~j +/- e~j e~i = B(i, j) + B(j, i)*/ }; /** This class represents the Clifford algebra unity element. */ class diracone : public tensor { GINAC_DECLARE_REGISTERED_CLASS(diracone, tensor) // non-virtual functions in this class protected: void do_print(const print_context & c, unsigned level) const override; void do_print_latex(const print_latex & c, unsigned level) const; }; /** This class represents the Clifford algebra generators (units). */ class cliffordunit : public tensor { GINAC_DECLARE_REGISTERED_CLASS(cliffordunit, tensor) // other constructors protected: cliffordunit(tinfo_t ti) : inherited(ti) {} // functions overriding virtual functions from base classes public: bool contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const override; // non-virtual functions in this class protected: void do_print(const print_context & c, unsigned level) const override; void do_print_latex(const print_latex & c, unsigned level) const; }; /** This class represents the Dirac gamma Lorentz vector. */ class diracgamma : public cliffordunit { GINAC_DECLARE_REGISTERED_CLASS(diracgamma, cliffordunit) // functions overriding virtual functions from base classes public: bool contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const override; // non-virtual functions in this class protected: void do_print(const print_context & c, unsigned level) const override; void do_print_latex(const print_latex & c, unsigned level) const; }; /** This class represents the Dirac gamma5 object which anticommutates with * all other gammas. */ class diracgamma5 : public tensor { GINAC_DECLARE_REGISTERED_CLASS(diracgamma5, tensor) // functions overriding virtual functions from base classes ex conjugate() const override; // non-virtual functions in this class protected: void do_print(const print_context & c, unsigned level) const override; void do_print_latex(const print_latex & c, unsigned level) const; }; /** This class represents the Dirac gammaL object which behaves like * 1/2 (1-gamma5). */ class diracgammaL : public tensor { GINAC_DECLARE_REGISTERED_CLASS(diracgammaL, tensor) // functions overriding virtual functions from base classes ex conjugate() const override; // non-virtual functions in this class protected: void do_print(const print_context & c, unsigned level) const override; void do_print_latex(const print_latex & c, unsigned level) const; }; /** This class represents the Dirac gammaL object which behaves like * 1/2 (1+gamma5). */ class diracgammaR : public tensor { GINAC_DECLARE_REGISTERED_CLASS(diracgammaR, tensor) // functions overriding virtual functions from base classes ex conjugate() const override; // non-virtual functions in this class protected: void do_print(const print_context & c, unsigned level) const override; void do_print_latex(const print_latex & c, unsigned level) const; }; // global functions /** Check whether a given tinfo key (as returned by return_type_tinfo() * is that of a clifford object (with an arbitrary representation label). * * @param ti tinfo key */ bool is_clifford_tinfo(tinfo_t ti); /** Create a Clifford unity object. * * @param rl Representation label * @return newly constructed object */ ex dirac_ONE(unsigned char rl = 0); /** Create a Clifford unit object. * * @param mu Index (must be of class varidx or a derived class) * @param metr Metric (should be indexed, tensmetric or a derived class, or a matrix) * @param rl Representation label * @return newly constructed Clifford unit object */ ex clifford_unit(const ex & mu, const ex & metr, unsigned char rl = 0); /** Create a Dirac gamma object. * * @param mu Index (must be of class varidx or a derived class) * @param rl Representation label * @return newly constructed gamma object */ ex dirac_gamma(const ex & mu, unsigned char rl = 0); /** Create a Dirac gamma5 object. * * @param rl Representation label * @return newly constructed object */ ex dirac_gamma5(unsigned char rl = 0); /** Create a Dirac gammaL object. * * @param rl Representation label * @return newly constructed object */ ex dirac_gammaL(unsigned char rl = 0); /** Create a Dirac gammaR object. * * @param rl Representation label * @return newly constructed object */ ex dirac_gammaR(unsigned char rl = 0); /** Create a term of the form e_mu * gamma~mu with a unique index mu. * * @param e Original expression * @param dim Dimension of index * @param rl Representation label */ ex dirac_slash(const ex & e, const ex & dim, unsigned char rl = 0); /** Calculate dirac traces over the specified set of representation labels. * The computed trace is a linear functional that is equal to the usual * trace only in D = 4 dimensions. In particular, the functional is not * always cyclic in D != 4 dimensions when gamma5 is involved. * * @param e Expression to take the trace of * @param rls Set of representation labels * @param trONE Expression to be returned as the trace of the unit matrix */ ex dirac_trace(const ex & e, const std::set & rls, const ex & trONE = 4); /** Calculate dirac traces over the specified list of representation labels. * The computed trace is a linear functional that is equal to the usual * trace only in D = 4 dimensions. In particular, the functional is not * always cyclic in D != 4 dimensions when gamma5 is involved. * * @param e Expression to take the trace of * @param rll List of representation labels * @param trONE Expression to be returned as the trace of the unit matrix */ ex dirac_trace(const ex & e, const lst & rll, const ex & trONE = 4); /** Calculate the trace of an expression containing gamma objects with * a specified representation label. The computed trace is a linear * functional that is equal to the usual trace only in D = 4 dimensions. * In particular, the functional is not always cyclic in D != 4 dimensions * when gamma5 is involved. * * @param e Expression to take the trace of * @param rl Representation label * @param trONE Expression to be returned as the trace of the unit matrix */ ex dirac_trace(const ex & e, unsigned char rl = 0, const ex & trONE = 4); /** Bring all products of clifford objects in an expression into a canonical * order. This is not necessarily the most simple form but it will allow * to check two expressions for equality. */ ex canonicalize_clifford(const ex & e); /** Automorphism of the Clifford algebra, simply changes signs of all * clifford units. */ ex clifford_prime(const ex & e); /** Main anti-automorphism of the Clifford algebra: makes reversion * and changes signs of all clifford units. */ inline ex clifford_bar(const ex & e) { return clifford_prime(e.conjugate()); } /** Reversion of the Clifford algebra, coincides with the conjugate(). */ inline ex clifford_star(const ex & e) { return e.conjugate(); } /** Replaces dirac_ONE's (with a representation_label no less than rl) in e with 1. * For the default value rl = 0 remove all of them. Aborts if e contains any * clifford_unit with representation_label to be removed. * * @param e Expression to be processed * @param rl Value of representation label * @param options Defines some internal use */ ex remove_dirac_ONE(const ex & e, unsigned char rl = 0, unsigned options = 0); /** Returns the maximal representation label of a clifford object * if e contains at least one, otherwise returns -1 * * @param e Expression to be processed * @ignore_ONE defines if clifford_ONE should be ignored in the search*/ int clifford_max_label(const ex & e, bool ignore_ONE = false); /** Calculation of the norm in the Clifford algebra. */ ex clifford_norm(const ex & e); /** Calculation of the inverse in the Clifford algebra. */ ex clifford_inverse(const ex & e); /** List or vector conversion into the Clifford vector. * * @param v List or vector of coordinates * @param mu Index (must be of class varidx or a derived class) * @param metr Metric (should be indexed, tensmetric or a derived class, or a matrix) * @param rl Representation label * @param e Clifford unit object * @return Clifford vector with given components */ ex lst_to_clifford(const ex & v, const ex & mu, const ex & metr, unsigned char rl = 0); ex lst_to_clifford(const ex & v, const ex & e); /** An inverse function to lst_to_clifford(). For given Clifford vector extracts * its components with respect to given Clifford unit. Obtained components may * contain Clifford units with a different metric. Extraction is based on * the algebraic formula (e * c.i + c.i * e)/ pow(e.i, 2) for non-degenerate cases * (i.e. neither pow(e.i, 2) = 0). * * @param e Clifford expression to be decomposed into components * @param c Clifford unit defining the metric for splitting (should have numeric dimension of indices) * @param algebraic Use algebraic or symbolic algorithm for extractions * @return List of components of a Clifford vector*/ lst clifford_to_lst(const ex & e, const ex & c, bool algebraic=true); /** Calculations of Moebius transformations (conformal map) defined by a 2x2 Clifford matrix * (a b\\c d) in linear spaces with arbitrary signature. The expression is * (a * x + b)/(c * x + d), where x is a vector build from list v with metric G. * (see Jan Cnops. An introduction to {D}irac operators on manifolds, v.24 of * Progress in Mathematical Physics. Birkhauser Boston Inc., Boston, MA, 2002.) * * @param a (1,1) entry of the defining matrix * @param b (1,2) entry of the defining matrix * @param c (2,1) entry of the defining matrix * @param d (2,2) entry of the defining matrix * @param v Vector to be transformed * @param G Metric of the surrounding space, may be a Clifford unit then the next parameter is ignored * @param rl Representation label * @return List of components of the transformed vector*/ ex clifford_moebius_map(const ex & a, const ex & b, const ex & c, const ex & d, const ex & v, const ex & G, unsigned char rl = 0); /** The second form of Moebius transformations defined by a 2x2 Clifford matrix M * This function takes the transformation matrix M as a single entity. * * @param M the defining matrix * @param v Vector to be transformed * @param G Metric of the surrounding space, may be a Clifford unit then the next parameter is ignored * @param rl Representation label * @return List of components of the transformed vector*/ ex clifford_moebius_map(const ex & M, const ex & v, const ex & G, unsigned char rl = 0); } // namespace GiNaC #endif // ndef __GINAC_CLIFFORD_H__ pynac-pynac-0.6.0/ginac/compiler.h000066400000000000000000000004341264176364700170240ustar00rootroot00000000000000#ifndef GINAC_COMPILER_DEP_HH #define GINAC_COMPILER_DEP_HH #ifdef __GNUC__ #define unlikely(cond) __builtin_expect((cond), 0) #define likely(cond) __builtin_expect((cond), 1) #else #define unlikely(cond) (cond) #define likely(cond) (cond) #endif #endif /* GINAC_COMPILER_DEP_HH */ pynac-pynac-0.6.0/ginac/constant.cpp000066400000000000000000000155371264176364700174100ustar00rootroot00000000000000/** @file constant.cpp * * Implementation of GiNaC's constant types and some special constants. */ /* * GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "py_funcs.h" #include "constant.h" #include "numeric.h" #include "ex.h" #include "archive.h" #include "utils.h" #include "inifcns.h" #include #include #include namespace GiNaC { GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(constant, basic, print_func(&constant::do_print). print_func(&constant::do_print_latex). print_func(&constant::do_print_tree). print_func(&constant::do_print_python_repr)) ////////// // default constructor ////////// // public constant::constant() : basic(&constant::tinfo_static), ef(nullptr), serial(next_serial++), domain(domain::complex) { setflag(status_flags::evaluated | status_flags::expanded); } ////////// // other constructors ////////// // public constant::constant(std::string initname, evalffunctype efun, const std::string & texname, unsigned dm) : basic(&constant::tinfo_static), name(std::move(initname)), ef(efun), serial(next_serial++), domain(dm) { if (texname.empty()) TeX_name = "\\mbox{" + name + "}"; else TeX_name = texname; setflag(status_flags::evaluated | status_flags::expanded); } constant::constant(std::string initname, const numeric & initnumber, const std::string & texname, unsigned dm) : basic(&constant::tinfo_static), name(std::move(initname)), ef(nullptr), number(initnumber), serial(next_serial++), domain(dm) { if (texname.empty()) TeX_name = "\\mbox{" + name + "}"; else TeX_name = texname; setflag(status_flags::evaluated | status_flags::expanded); } ////////// // archiving ////////// constant::constant(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst) {} ex constant::unarchive(const archive_node &n, lst &sym_lst) { // Find constant by name (!! this is bad: 'twould be better if there // was a list of all global constants that we could search) constant ans; std::string s; if (n.find_string("name", s)) { if (s == Pi.name) return Pi; else if (s == Catalan.name) return Catalan; else if (s == Euler.name) return Euler; else { ans = py_funcs.py_get_constant(s.c_str()); if (PyErr_Occurred()) { throw std::runtime_error("error while unarchiving constant"); } } //throw (std::runtime_error("unknown constant '" + s + "' in archive")); return ans; } else throw (std::runtime_error("unnamed constant in archive")); } void constant::archive(archive_node &n) const { inherited::archive(n); n.add_string("name", name); } ////////// // functions overriding virtual functions from base classes ////////// // public void constant::do_print(const print_context & c, unsigned level) const { c.s << name; } void constant::do_print_tree(const print_tree & c, unsigned level) const { c.s << std::string(level, ' ') << name << " (" << class_name() << ")" << " @" << this << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec << std::endl; } void constant::do_print_latex(const print_latex & c, unsigned level) const { c.s << TeX_name; } void constant::do_print_python_repr(const print_python_repr & c, unsigned level) const { c.s << class_name() << "('" << name << "'"; if (TeX_name != "\\mbox{" + name + "}") c.s << ",TeX_name='" << TeX_name << "'"; c.s << ')'; } bool constant::info(unsigned inf) const { if (inf == info_flags::polynomial) return true; if (inf == info_flags::inexact) return false; if (inf == info_flags::real) return domain==domain::real || domain==domain::positive ; if (inf==info_flags::positive || inf==info_flags::nonnegative) return domain == domain::positive; if (inf==info_flags::infinity) { return domain == domain::infinity; } else return inherited::info(inf); } ex constant::evalf(int level, PyObject* parent) const { if (ef!=nullptr) { return ef(serial, parent); } else { return number.evalf(level, parent); } return *this; } bool constant::is_polynomial(const ex & var) const { return true; } ex constant::conjugate() const { if ( domain==domain::real || domain==domain::positive ) return *this; return conjugate_function(*this).hold(); } ex constant::real_part() const { if ( domain==domain::real || domain==domain::positive ) return *this; return real_part_function(*this).hold(); } ex constant::imag_part() const { if ( domain==domain::real || domain==domain::positive ) return 0; return imag_part_function(*this).hold(); } // protected /** Implementation of ex::diff() for a constant always returns 0. * * @see ex::diff */ ex constant::derivative(const symbol & s) const { return _ex0; } int constant::compare_same_type(const basic & other) const { GINAC_ASSERT(is_exactly_a(other)); const constant &o = static_cast(other); if (serial == o.serial) return 0; else return serial < o.serial ? -1 : 1; } bool constant::is_equal_same_type(const basic & other) const { GINAC_ASSERT(is_exactly_a(other)); const constant &o = static_cast(other); return serial == o.serial; } long constant::calchash() const { hashvalue = golden_ratio_hash((p_int)tinfo() ^ serial); setflag(status_flags::hash_calculated); return hashvalue; } ////////// // new virtual functions which can be overridden by derived classes ////////// // none ////////// // non-virtual functions in this class ////////// // none ////////// // static member variables ////////// unsigned constant::next_serial = 0; ////////// // global constants ////////// /** Pi. (3.14159...) Calls python function py_eval_constant() for evalf(). */ const constant Pi("pi", ConstantEvalf, "\\pi", domain::positive); /** Euler's constant. (0.57721...) Sometimes called Euler-Mascheroni constant. * Calls python function py_eval_consant for evalf(). */ const constant Euler("euler_gamma", ConstantEvalf, "\\gamma_E", domain::positive); /** Catalan's constant. (0.91597...) * Calls python function py_eval_constant for evalf(). */ const constant Catalan("catalan", ConstantEvalf, "G", domain::positive); } // namespace GiNaC pynac-pynac-0.6.0/ginac/constant.h000066400000000000000000000061701264176364700170460ustar00rootroot00000000000000/** @file constant.h * * Interface to GiNaC's constant types and some special constants. */ /* * GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __GINAC_CONSTANT_H__ #define __GINAC_CONSTANT_H__ #include "basic.h" #include "ex.h" #include namespace GiNaC { typedef ex (*evalffunctype)(unsigned serial, PyObject* parent); /** This class holds constants, symbols with specific numerical value. Each * object of this class must either provide their own function to evaluate it * to class numeric or provide the constant as a numeric (if it's an exact * number). */ class constant : public basic { GINAC_DECLARE_REGISTERED_CLASS(constant, basic) // member functions // other constructors public: constant(std::string initname, evalffunctype efun = nullptr, const std::string & texname = std::string(), unsigned domain = domain::complex); constant(std::string initname, const numeric & initnumber, const std::string & texname = std::string(), unsigned domain = domain::complex); // functions overriding virtual functions from base classes public: bool info(unsigned inf) const override; ex evalf(int level = 0, PyObject* parent=nullptr) const override; bool is_polynomial(const ex & var) const override; ex conjugate() const override; ex real_part() const override; ex imag_part() const override; unsigned get_serial() const {return serial;} protected: ex derivative(const symbol & s) const override; bool is_equal_same_type(const basic & other) const override; long calchash() const override; // non-virtual functions in this class protected: void do_print(const print_context & c, unsigned level) const override; void do_print_tree(const print_tree & c, unsigned level) const override; void do_print_latex(const print_latex & c, unsigned level) const; void do_print_python_repr(const print_python_repr & c, unsigned level) const override; // member variables private: std::string name; ///< printname of this constant std::string TeX_name; ///< LaTeX name evalffunctype ef; ex number; ///< numerical value this constant evalf()s to unsigned serial; ///< unique serial number for comparison static unsigned next_serial; unsigned domain; ///< numerical value this constant evalf()s to }; extern const constant Pi; extern const constant Catalan; extern const constant Euler; } // namespace GiNaC #endif // ndef __GINAC_CONSTANT_H__ pynac-pynac-0.6.0/ginac/container.h000066400000000000000000000604061264176364700172010ustar00rootroot00000000000000/** @file container.h * * Wrapper template for making GiNaC classes out of STL containers. */ /* * GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __GINAC_CONTAINER_H__ #define __GINAC_CONTAINER_H__ #include "ex.h" #include "print.h" #include "archive.h" #include "assertion.h" #include #include #include #include #include #include #include namespace GiNaC { /** Helper template for encapsulating the reserve() mechanics of STL containers. */ template